题目描述
四平方和定理,又称为拉格朗日定理:
每个正整数都可以表示为至多 4
个正整数的平方和。
如果把 0
包括进去,就正好可以表示为 4
个数的平方和。
比如:
5=0^2+0^2+1^2+2^2
7=1^2+1^2+1^2+2^2
对于一个给定的正整数,可能存在多种平方和的表示法。
要求你对 4
个数排序:
0≤a≤b≤c≤d
并对所有的可能表示法按 a,b,c,d
为联合主键升序排列,最后输出第一个表示法。
输入格式
输入一个正整数 N
。
输出格式
输出4个非负整数,按从小到大排序,中间用空格分开。
数据范围
0<N<5∗10^6
样例
输入样例:
5
输出样例:
0 0 1 2
算法1
(暴力枚举) $O(n^3)$
思路比较简单,就是一个简单的循环遍历
三重循环
C++ 代码
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,a,b,c,d;
scanf("%d",&n);
int sqn = int(sqrt(n));
for(a=0;a<=sqn;++a)
{
for(b=a;b<=sqn;++b)
{
for(c=b;c<=sqn;++c)
{
d=sqrt(n-a*a-b*b-c*c); //这里可以有效地减少一重循环
if(n==a*a+b*b+c*c+d*d)
{
if(c>d)swap(d,c);
printf("%d %d %d %d\n",a,b,c,d);
return 0;
}
}
}
}
}
由于Java的jvm时间比c++的时间多一倍,所以我们可以循环遍历!
Java 代码
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
for(int a=0;a<=Math.sqrt(n);a++){
for(int b=a;b<=Math.sqrt(n);b++){
for(int c=b;c<=Math.sqrt(n);c++){
for(int d=c;d<=Math.sqrt(n);d++){
if((a*a+b*b+c*c+d*d)==n){
System.out.println(a+" "+b+" "+c+" "+d);
return;
}
}
}
}
}
}
}
四平方和问题优化:
思路:
减少枚举变量
确定枚举范围:
a 0–sqrt(510^6/4)
b 0–sqrt(510^6/3)
c 0–sqrt(510^6/2)
d 0–sqrt(510^6)
预先求出R=c^2+d^2的解 用unordered_map来保存一个R对应的c。也就是构建哈希表
优化枚举
(哈希+枚举) $O(n^2)$
有效减少了枚举,当然还有一种思路就是用二进制去解决它,时间复杂度可以优化到O(nlogn)
C++ 代码
#include <iostream>
#include <unordered_map>
#include <cmath>
using namespace std;
int n;
unordered_map <int, int> f;
int main()
{
cin >> n;
for (int c = 0; c*c <= n / 2;c++)
{
for (int d = c; c*c + d*d <= n;d++)
{
//如果没有找到,将数据保存
if (f.find(c*c+d*d)==f.end())
{
f[c*c + d*d] = c;
}
}
}
for (int a = 0; a*a * 4 <= n;a++)
{
for (int b = a; a*a + b*b <= n / 2;b++)
{
if (f.find(n - a*a - b*b) != f.end())
{
int c = f[n - a*a - b*b];
int d = int(sqrt(n - a*a - b*b - c*c)*1.0);
cout << a << " " << b << " " << c << " " << d << endl;
return 0;
}
}
}
return 0;
}
现在这题数据优化后map也过不了了 QAQ
是啊 哈希也过不了
为什么这个O(N^2)还是会超时…假的O(N^2)吗😂
正常啊,N<5∗10^6
哦哦 确实你说的有道理,但是最后一个优化枚举也是N^2为啥就能过嘞
$O(n^2)$的做法,好妙,y总说这个 可以不用unordered_map,可以直接开数组
这个空间换时间优化大吗? ^-^
先问下Java中暴力枚举方法中如果<=Math.sqrt(n)改为<n会是奇怪的答案呢?
数据加强过了,不能暴力了
/4 /3 /2 确实是优化了一下 偶尔能过 大部分时间过不了 还是二分吧
直接暴力,三重循环已经过不了了吧
直播讲过 可以的
这样吗?是不是后来优化数据了?我写的代码就过不了,后来我直接把你的代码复制过去还是超时的啊,难道是我搞错了?
yls把数据加强了
那估计只能二分了吧,哈希也过不了了
int(sqrt(n - aa - bb - cc)1.0);
为啥要乘1.0呀
防止精度损失
if(c>d)swap(d,c); 就算交换了也不能保证a<b<c<d呀
循环条件有限制/!!
为啥d一定大于a,b呢?
其实我觉得下面那个算法在建哈希表的时候,调用了find,这个花费的时间也比较多,肯定不是n^2的算法了
大概是这样,而且他的数量级就是O(n^2),hhhhh
unordered_map的find函数时间复杂度是O(1)的;
这个解析很精练