四平方和(多种解法)

注意,会列举过不了的一些思路

四平方和

四平方和定理,又称为拉格朗日定理:每个正整数都可以表示为至多 44 个正整数的平方和。

如果把 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

输入样例:
5
输出样例:
0 0 1 2

 1.首先,这个人试图用暴力,但是不出所料的TLE了

#include 
#include 
#include 
#include 
using namespace std;
const int N = 2500010;
int n;
int main()
{
	cin >> n;
	for(int a = 0;a * a <= n; a ++)
		for(int b = a;a * a + b * b <= n;b ++)
			for(int c = b;a * a + b * b + c * c <= n;c ++)
			{
				int t = n - a * a - b * b - c * c;
				int d = sqrt(t);
				if (d * d == t)
				{
					printf("%d %d %d %d\n",a,b,c,d);
					return 0;
				}
			}
}

然后重新思考题目

既然TLE,我们想到用空间换时间,不要用三重循环,只能用到二重。

因此我们把c,d放一块遍历,先存这部分的值,即t = n - c*c - d*d 

然后再遍历a,b,查找这个出现过的 t 每出现一次是一种表示法

接下来我们思考如何按照字典序升序排列,找到最小那种

a,b在遍历的时候按照从小到大遍历,枚举时已经确定,并且是最小的

然后我们要找的就是找到 t 时,从c, d 的字典序最小

这就需要查找,提起查找一般两个思路

· 哈希表  O(1)

· 二分  O(log n)

2.接下来先用哈希表的方法写一下

#include 
#include 
#include 
#include 
using namespace std;

#define x first
#define y second
typedef pair PII
int n;
unordered_map s;

int main()
{
	cin >> n;
	for(int c = 0;c * c <= n; c ++)
		for(int d = c; c * c + d * d <= n; d ++)
		{
			int t = c * c + d * d;
			if(s.count(t) == 0) s[t] = {c, d};//找到存第一次就是最小的
		}
		
	for(int a = 0;a * a <= n;a ++)
		for(int b = a;a * a + b * b <= n; b ++)
		{
			int t = n - a * a + b * b;
			if(s.count(t))
			{
				printf("%d %d %d %d\n", a, b, s[t].x, s[t].y);
				return 0;
			}
		}	
}

但是 !这个也TLE了

However 用模拟哈希可以过

就是用int s[N * 2]; 避免pair,s[c^2+d^2]=c,可以利用这个推导出d

#include 
#include 
#include 
#include 
#include 
using namespace std;

typedef pair PII;
const int N = 5000010;
int n;
int s[N * 2];

int main()
{
	cin >> n;
	memset(s, -1, sizeof(s));//初始化 
	
	for(int c = 0;c * c <= n; c ++)
		for(int d = c; c * c + d * d <= n; d ++)
		{
			int t = c * c + d * d;
			if(s[t] == -1) s[t] = c;
		}
		
	for(int a = 0;a * a <= n;a ++)
		for(int b = a;a * a + b * b <= n; b ++)
		{
			int t = n - a * a - b * b;
			int c = s[t];
			if(s[t] == -1) continue;
			//说明不存在满足c^2 + d^2 = t 的 c,d,则跳过当前循环,继续下一次循环。
			int d = sqrt(t - c * c);
			printf("%d %d %d %d\n", a, b, c, d);
			
			return 0;
			
		}	
}

 3.二分

#include 
#include 
#include 
using namespace std;

const int N = 5e6 + 10;
int n, m;
struct Sum
{
	int s, c, d;//s存c^2+d^2结果
	bool operator<(const Sum &t)const //运算符重载 
	{
		if(s != t.s)  return s < t.s; //如果s不相同,返回较小那个 
		if(c != t.c)  return c < t.c; //如果c不相同,返回较小那个
		return d < t.d; // 否则返回d较小的 
	} 

}sum[N];

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 = a;a * a + b * b <= n; b ++)
		{
			int t = n - a * a - b * b;
			int l = 0,r = m;
			while(l < r)
			{
				int mid = l + r >> 1;// 左移1位就是除以2 
				if(sum[mid].s >= t)  r = mid;
				else l = mid + 1;
			}
			if(sum[l].s == t)
			{
				printf("%d %d %d %d\n", a, b, sum[l].c, sum[l].d);
				return 0;
			}
			
		}
}

你可能感兴趣的:(算法,数据结构,哈希算法,c++)