四平方和定理,又称为拉格朗日定理:
每个正整数都可以表示为至多 4 个正整数的平方和。
如果把 0 包括进去,就正好可以表示为 4 个数的平方和。
比如:
5=02+02+12+22
7=12+12+12+22
对于一个给定的正整数,可能存在多种平方和的表示法。
要求你对 4 个数排序:
0≤a≤b≤c≤d
并对所有的可能表示法按 a,b,c,d 为联合主键升序排列,最后输出第一个表示法。
输入格式
输入一个正整数 N。
输出格式
输出4个非负整数,按从小到大排序,中间用空格分开。
数据范围
0<N<5∗106
输入样例:
5
输出样例:
0 0 1 2
题目思路:
二分法降低时间复杂度
用打表空间换时间
使得O(n3)的算法降低为O(n2logn)成功通过
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N = 5000000;
struct Sum
{
int s,c,d;
bool operator < (Sum &t) const{
if(s!=t.s) return s < t.s;
if(c!=t.c) return c < t.c;
return d < t.d;
}
}snum[N];
int cnt;
int search_left(struct Sum s[],int n,int target)
{
int l = 0,r = n;
while(l < r)
{
int mid = (l + r)/2;
if(s[mid].s < target){
l = mid + 1;
}
else if(s[mid].s > target){
r = mid;
}
else if(s[mid].s == target){
r = mid;
}
}
if(l == n) return -1;
return s[l].s == target ? l : -1;
}
int main()
{
int n;
cin>>n;
int t = sqrt(n);
for(int c=0; c<=t; ++c){
for(int d=c; c*c+d*d<=n; ++d){
snum[cnt++] = {c*c+d*d,c,d};
}
}
sort(snum,snum+cnt);
for(int a=0; a<=t; ++a)
{
for(int b=a; b*b+a*a<=n; ++b){
int t = n - b*b - a*a;
int index = search_left(snum,cnt,t);
if(index==-1) continue;
else{
cout<<a<<' '<<b<<' '<<snum[index].c<<' '<<snum[index].d<<' '<<endl;
return 0;
}
}
}
return 0;
}