[HAOI2008]圆上的整点
Description
求一个给定的圆(x2+y2=r^2),在圆周上有多少个点的坐标是整数。
Input
只有一个正整数n,n<=2000 000 000
Output
整点个数
Sample Input
4
Sample Output
4
这种题肯定是要推柿子的啦~~~
\(X^2+Y^2=R^2\)
\(Y^2=(R-X)(R+X)\)
令\(d=gcd(R-X,R+X),A=\dfrac{R-X}{d},B=\dfrac{R+X}{d}\)
所以\(y^2=d^2\times A\times B\)
因为\(y^2,d^2\)为完全平方数,因此\(A\times B\)也为完全平方数
由于\(gcd(A,B)=1\),因此\(A,B\)本身也是完全平方数
令\(a^2=A,b^2=B\),由于\(gcd(A,B)=1\),因此\(A\ne B\),因此\(a\ne b\)
我们令\(a<b\),则可以得到\(a^2=\dfrac{R-X}{d},b^2=\dfrac{R+X}{d}\)
相加可得\(a^2+b^2=\dfrac{2R}{d}\),因此\(d\)为\(2R\)的约数
于是我们可以在\(\sqrt{2R}\)的时间内枚举其约数,由于\(2a^2<\dfrac{2R}{d}\),因此我们可以直接枚举\(a\in[1,\sqrt{\dfrac{R}{d}}]\),然后计算出\(b\),再将其反代回求出\(A,B\),判断\(A,B\)是否满足条件
但是这样子我们只算出了处于第一象限的答案,根据圆的对称性,我们需要将答案乘上4,并且加上坐标轴上的4个点
/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline char gc(){
static char buf[1000000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
inline int frd(){
int x=0,f=1; char ch=gc();
for (;ch<'0'||ch>'9';ch=gc()) if (ch=='-') f=-1;
for (;ch>='0'&&ch<='9';ch=gc()) x=(x<<3)+(x<<1)+ch-'0';
return x*f;
}
inline int read(){
int x=0,f=1; char ch=getchar();
for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1;
for (;ch>='0'&&ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+ch-'0';
return x*f;
}
inline void print(int x){
if (x<0) putchar('-'),x=-x;
if (x>9) print(x/10);
putchar(x%10+'0');
}
ll R,Ans;
ll gcd(ll a,ll b){return !b?a:gcd(b,a%b);}
bool check(int a,int b){
ll A=1ll*a*a,B=1ll*b*b;
return (gcd(A,B)==1)&&(A!=B);
}
void work(ll x){
for (int a=1;a*a<=x>>1;a++){
int b=trunc(sqrt(x-a*a));
if (1ll*a*a+1ll*b*b!=x) continue;
if (check(a,b)) Ans++;
}
}
int main(){
R=2ll*read();
for (int i=1;1ll*i*i<=R;i++){
if (R%i) continue;
work(i);
if (R/i!=i) work(R/i);
}
printf("%lld\n",4*Ans+4);
}