problem
求一个给定的圆( x2+y2=r2 x 2 + y 2 = r 2 ),在圆周上有多少个点的坐标是整数。
Input
只有一个正整数r,r<=2000 000 000
Output
整点个数
Sample Input
4
Sample Output
4
Hint
思路
显然,对于所给半径r,对应四个坐标轴上的点一定在圆 x2+y2=r2 x 2 + y 2 = r 2 上;而对于四个象限内的坐标,问题转化为求解二次方程 x2+y2=r2 x 2 + y 2 = r 2 的整数解,其中 x>0,y>0 x > 0 , y > 0 。记所得解组数为n,由对称性则ans=(n+1)*4
x2+y2=r2 x 2 + y 2 = r 2 方程有多少组整数解?,其中r的范围为 2∗109 2 ∗ 10 9
易想到的做法是对x进行 [1,r22‾‾‾√] [ 1 , r 2 2 ] 的枚举,判断是否存在y,y∈ N+ N + 满足方程。
但注意到r的范围,这种方法会超时。
下面这种方法,利用了互质数的特殊性质,可以将等式简化,从而降低复杂度
设x∗x+y∗y=r2则y2=r2−x2=(r+x)(r−x)设d=gcd(r+x,r−x),则gcd(r+xd,r−xd)=1 设 x ∗ x + y ∗ y = r 2 则 y 2 = r 2 − x 2 = ( r + x ) ( r − x ) 设 d = g c d ( r + x , r − x ) , 则 g c d ( r + x d , r − x d ) = 1
记A=r+xd,B=r−xd 记 A = r + x d , B = r − x d ,即A,B是互质的。我们利用同除以gcd的方法构造出了互质的两个数A,B ,将其带入上面*式,则得 A∗B∗d2=y2,A∗B=(yd)2 A ∗ B ∗ d 2 = y 2 , A ∗ B = ( y d ) 2 ,又由于d|y(因为r+x,r-x中都含有d这个因子),所以得到 A∗B A ∗ B 为完全平方数。又因为A,B是互质的,所以A,B本身都是完全平方数。(下面给出这个性质的证明)
已知两个数A,B是互质的,且 A∗B=C2,C为整数 A ∗ B = C 2 , C 为 整 数 ,则A,B本身都是完全平方数
证明:由于A,B是互质的,则分解质因数后,他们不含有公共的因数 p p 。A,B相乘,由于没有相同的底数,则相当于把两个质因数直接“拼接”在一起。而现在这个数是完全平方数,即每个指数都是偶数,因此原先A,B质因子分解的每个指数也是偶数。得证。
接着这题,设,因此 a2+b2=2rd a 2 + b 2 = 2 r d 。因此只有当d|2r时,这个等式才有解,也就等价于 x∗x+y∗y=r2 x ∗ x + y ∗ y = r 2 有解。所以我们枚举 {d|d|2r} { d | d | 2 r } ,得到2r的两个因子(一大一小,成对出现),记为x,y。再去解方程 a2+b2=xa2+b2=y a 2 + b 2 = x a 2 + b 2 = y 即可(解这两个方程用普通根号折中枚举方法)。
总的复杂度约为 O(2r√常数)∗[O(d2‾‾√)+O(rd‾‾√)] O ( 2 r 常 数 ) ∗ [ O ( d 2 ) + O ( r d ) ] ,其中常数的大小由r的因子数决定。
代码示例
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b)
{
if(b==0) return a;
return gcd(b,a%b);
}
bool judge_Coprime(ll a,ll b)
{
if(gcd(a,b)==1&&a!=b) return true;
else return false;
}
int main()
{
ios::sync_with_stdio(false);
ll r;
cin>>r;
ll ans=0;
for(ll d=1;d<=(ll)sqrt(2*r);++d){
if(2*r%d==0){
// cout<<"d是"<<d<<": ";
for(ll b=1;b<=(ll)sqrt(d*1.0/2.0);++b){
ll a=(ll)sqrt(d-b*b);
//cout<<"① a、b是: "<<a<<' '<<b<<endl;
if((a*a+b*b==d)&&(judge_Coprime(a,b)==1)) ans++;
}
for(ll b=1;b<=(ll)sqrt(r*1.0/d);++b){
ll a=(ll)sqrt(2*r*1.0/d-b*b);
//cout<<"② a、b是: "<<a<<' '<<b<<' '<<endl;
if((a*a+b*b==2*r/d)&&(judge_Coprime(a,b)==1)) ans++;
}
}
}
cout<<4*(ans+1)<<endl;
return 0;
}
总结
两个互质的数相乘为一完全平方数,则这两个数为完全平方数