四平方和:
题目描述:
四平方和定理,又称为拉格朗日定理: 每个正整数都可以表示为至多 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
不知道这个题在比赛中暴力能不能过,因为尝试之后发现其实枚举的次数并不太多,最大的时候好像是 4999992。暴力代码一般都会,第二种方法是用二分,有点没想到。所以两种方法都分享一下。
暴力枚举,复杂度O(n^3)
#include <cstdio>
#include <cmath>
#include <cstring>
#include <iostream>
#include <algorithm>
typedef long long LL;
using namespace std;
const int MAXN = 1e7;
int a[5], n;
// 暴力做法 O(n^3)
int main() {
cin >> n;
int a, b, c, d;
for(a = 0; a*a <= n; a++) {
for(b = a; b*b + a*a <= n; b++) {
for(c = b; c*c + b*b + a*a <= n; c++) {
d = (int)sqrt((double)n - a*a + b*b + c*c);
if(a*a + b*b + c*c + d*d == n) {
printf("%d %d %d %d\n", a, b, c, d);
break;
}
}
}
}
return 0;
}
二分
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
typedef long long LL;
using namespace std;
const int MAXN = 2500010;
struct Node{
int s, c, d;
bool operator < (const Node &t)const {
if(s != t.s) return s < t.s;
if(c != t.c) return c < t.c;
return d < t.d;
}
}sum[MAXN];
int n, m;
int main() {
cin >> n;
for(int c = 0; c * c <= n; c++)
for(int d = c; c * c + d * d <= n; d++)
sum[m++] = {c*c + d*d, c, d};
sort(sum, sum+m);
for(int a = 0; a * a <= n; a++) {
for(int b = 0; a * a + b * b <= n; b++) {
int t = n - a * a - b * b;
int l = 0, r = m-1;
while(l < r) {
int mid = l + r >> 1;
if(sum[mid].s >= t) r = mid;
else l = mid + 1;
}
// 找到字典序最小的
if(sum[l].s == t) {
printf("%d %d %d %d", a, b, sum[l].c, sum[l].d);
return 0;
}
}
}
return 0;
}