勾股数

这道题是一对兄弟在几个夜晚里想出来的idea:

【哥:KoSaking,弟:osfly

弟:哥,这是什么?(指着哥哥远古小本子上的一行字)

哥:哦,那是我初三上课无聊时想的一个“定律”,还没证明,也懒得证明。

弟弟拿出了草稿纸和笔,不到五分钟就证完了。

弟:还挺好证的。

哥:是吗,我不知道。


“定律”原文:

y=x+1a=x+yb=x2+y21c=x2+y2

a,b,c 为一组勾股数。

简证:将 y=x+1 代入后面几个式子硬算可得出。


弟:可是它不是强定律捏,看看能不能把这个 1 消去吧。

哥弟俩花了大概10分钟。

哥:嗯,这个应该没错了。


“强定律”原文:

y=x+n(n | 2x2 , {x,y,n}N)a=x+yb=x2+y2nnc=x2+y2n

a,b,c 为一组勾股数。

证明方法和“非强定律”的证明方法一致。


哥:诶,那如果给定一条边,根据这个定律可以构造出所有的勾股数吗?

弟:……好像可以,如果这条边是 a 的话可以暴力枚举 x,y,确定 x,y 就能确定 b,也就能确定 c 了。

哥:试一试?

弟弟打开了电脑,噼里啪啦了大概20分钟,验证了其正确性。弟弟兴奋不已。

哥:那如果是斜边呢?

两人沉默了一会。

哥:我知道了,b2 挪到 c2 那边去,开个根号,bcn 代替,把 (cn)2 的括号拆出来,合并一下就能得到 2cnn2,这时候枚举 n 就可以了。

弟弟在刚刚的代码里添加了几行,证明是正确的,两个人十分高兴。

弟:也就是说,现在我们给出一个 n,就能在 O(n) 的时间复杂度里弄出来所有包含这条边的勾股数了,对吧。

哥:对。


形式化的题解:

回到问题,先来分析 pa 的情况:

p=a,我们来将 p 拆解为 x+y=2x+n 的形式。

a2+b2=c2a2=c2b2a2=(c+b)(cb)

根据定理,将其化作:

a2=n(b+c)b+c=a2n

要想求出所有可能的勾股数,即我们要 求出 b+c 的所有可能性,枚举 xn 均可。

易知此时 n 的范围为 1p1,所以时间复杂度为 O(p)

pb 的情况同理。

再来分析 pc 的情况:

p=c,根据定理得:

a2=c2b2a=c2b2=c2(cn)2=c2c2+2cnn2=2cnn2

要想求出所有可能的勾股数,即我们要 求出 a 的所有可能性,枚举 n 即可。

易知此时:

2cnn2>02cn>n2n<2c

所以 n 的范围为 12c,即12p,时间复杂度为 O(p)

综上,总时间复杂度为 O(p),带 3 倍常数,可以通过此题。

#include<cstdio>
#include<cmath>
#define int unsigned long long
int work(int p)
{
	int cnt=0,a,b,c,x,y,n;
	a=p;
//	for(x=1;x<=p-1;x++)//枚举x
//	{
//		y=a-x;
//		n=y-x;
//		if(n>0&&(2*x*x)%n==0)
//		{
//			b=(x*x+y*y)/n-n;
//			c=(x*x+y*y)/n;
//			cnt++;
//		}
//	}
	for(n=1;n<=p-1;n++)//枚举n
	{
		if((p-n)%2) continue;
		x=(p-n)/2;
		y=x+n;
		if(x<y&&(2*x*x)%n==0)
		{
			b=(x*x+y*y)/n-n;
			c=(x*x+y*y)/n;
			cnt++; 
		}
	}
	c=p;
	for(n=1;n<2*p;n++)
	{
		int tmp=2*c*n-n*n;
		int b=c-n;
		a=sqrt(tmp);
		if(a*a==tmp&&c>n&&a<b) cnt++;
	}
	return cnt;
}
signed main()
{
	int t;
	scanf("%llu",&t);
	while(t--)
	{
		int p;
		scanf("%llu",&p);
		printf("%llu\n",work(p));
	}
	return 0;
}
posted @   osfly  阅读(22)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示