1041: [HAOI2008]圆上的整点
Description
求一个给定的圆(x^2+y^2=r^2),在圆周上有多少个点的坐标是整数。
Input
只有一个正整数n,n<=2000 000 000
Output
整点个数
Sample Input
4
Sample Output
4
这道题是个喜闻乐见的推公式。。。。
显然枚举每个点是O(r)的。。。会T。。
然后对式子变形。。。
x^2+y^2=r^2→x^2=r^2-y^2=(r+y)(r-y)
我们不妨设d为r+y,r-y的最大公约数。。。则r+y=a^2*d,r-y=b^2*d
然后就可以得到:x^2=d^2*a^2*b^2
为什么是a^2和b^2因为要求x是整数啊,而且d是最大公因数,则a与b互素。。。。
r+y=a^2*d······①
r-y=b^2*d······②
①+②得:2*r=d(a^2+b^2)······③
因为d是r-y的因数,所以1<=d<sqrt(r/2)
如果满足条件,就枚举a,这时有两种情况,因为我们的d是小于sqrt(r/2)的。。。
所以除了d还有可能是2*r/d。。
根据③得到a的取值范围是1<=a^2<(r/d)或1<=a^2*2<d。。。
然后也可以算出b,只需判断b是否是整数并且与a互素就可以了。。。
需要注意的是因为我们算的只是四分之一圆的情况,所以答案要乘4,并且我们没有算x=0或y=0的情况,所以还要加4。。。
然后就解决了。。。
注意:会涉及到精度。。。对于类似x<sqrt(y)的式子可以变成x^2<y提高精度。。。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<cstdlib> 3 #include<cmath> 4 #include<cstring> 5 #include<cstdio> 6 #include<algorithm> 7 #include<string> 8 #include<map> 9 #include<queue> 10 #include<vector> 11 #include<set> 12 #define inf 1000000000 13 #define maxn 10000+5 14 #define maxm 10000+5 15 #define eps 1e-10 16 #define ll long long 17 #define for0(i,n) for(int i=0;i<=(n);i++) 18 #define for1(i,n) for(int i=1;i<=(n);i++) 19 #define for2(i,x,y) for(int i=(x);i<=(y);i++) 20 #define for3(i,x,y) for(int i=(x);i>=(y);i--) 21 #define for4(i,x) for(int i=head[x],y=e[i].go;i;i=e[i].next,y=e[i].go) 22 using namespace std; 23 int read(){ 24 int x=0,f=1;char ch=getchar(); 25 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 26 while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();} 27 return x*f; 28 } 29 ll gcd(ll a,ll b){if(b==0)return a;return gcd(b,a%b);} 30 int main(){ 31 //freopen("input.txt","r",stdin); 32 //freopen("output.txt","w",stdout); 33 ll r=read(),ans=0; 34 for(ll d=1;d*d<=2*r;d++){ 35 if((2*r)%d==0){ 36 for(ll a=1;a*a<r/d;a++){ 37 double b=sqrt(2*r/d-a*a); 38 if(b-(ll)b<=eps&&gcd(a,(ll)b)==1)ans++; 39 } 40 for(ll a=1;a*a*2<d;a++){ 41 double b=sqrt(d-a*a); 42 if(b-(ll)b<=eps&&gcd(a,(ll)b)==1)ans++; 43 } 44 } 45 } 46 printf("%lld",ans*4+4); 47 return 0; 48 }