数论题无力Orz...看了下题解,所以总结下吧,主要是运用gcd和分解质因数来进行优化。。
觉得写得很好,所以把题解搬过来了=。=
首先让我们一起来推下公式:
x^2+y^2=r^2
到这里为止应该都很容易想到,接下来是关键
设d=gcd(r-x,r+x)
设r-x=d*A
解释下,d已被提出,所以gcd(A,B)=1
而进一步,因为y^2=d^2*A*B,而gcd(A,B)=1
所以,我们可以这样表示:
A=a*a
B=b*b
(a<>b)
(因为y^2是平方数,d^2是平方数,所以可以这样化过来)
∴ r-x=d*a^2
①
①+②得 2r=d*(a^2+b^2)
d是2r的约数,所以我们可以用sqrt(2r)的时间枚举d,求出好多对d
我们设
d=d
d0=(2r)/d
我们可以用(sqrt(d)+sqrt(d0))的时间来枚举a,求出b,来对这一对d求解
思路应该清晰了吧
下面讲讲细节:
所以最后
ans=ans*4+4 (注意 不是ans*2+4,下面解释)
还有一个细节,在枚举a时实际的枚举范围是 a^2*2<2r/d
我们可以举一个例子
在r=1225中
我们可以算出的其中2个解为
d=490 a=1 b=2
d=490 a=1 b=2
d=490 a=2 b=1
没错,看起来好像a,b倒了一下,不一样
实际算到y中时
y^2=d(a^2+b^2)却成了同一个解
有些题解中最后会是*2而不是*4,就是因为这样(比如当年wjh大神给我们的题解)
这实际是写题解的人自己凑出,没搞清楚,或是没写清造成的
代码什么的就上我自己的好了(格式好乱)
#include<cmath>
#include<cstdio>
using namespace std;
long long r;
long long gcd(long long a,long long b)
{
return b==0?a:gcd(b,a%b);
}
int cal(int d)
{
int answer=0;
int d0=r/d;
for(int a=1;a*a*2<=d0;a++)
{
double tmp=sqrt(d0-a*a);
if(tmp==floor(tmp))
{
int b=(int)tmp;
if(gcd(a,b)==1 && a!=b) answer++;
}
}
return answer;
}
int main()
{
int ans=0;
scanf("%d",&r);
r*=2;
for(int i=1;i<=r/i;i++)
{
if(r%i==0)
{
if(r/i!=i)
ans=ans+cal(i)+cal(r/i);
else ans+=cal(i);
}
}
printf("%d",ans*4+4);
return 0;
}