题目描述
求一个给定的圆(x^2+y^2=r^2),在圆周上有多少个点的坐标是整数。
输入输出格式
输入格式:
r
输出格式:
整点个数
输入输出样例
输入样例#1:
4
输出样例#1:
4
说明
n<=2000 000 000
暴力很好打,但是这1000%是数论题。不就是推推式子嘛。
由于圆这个东西很棒棒,我们只需要考虑某一象限内的情况就行了。为了方便解题,我们取第一象限作研究对象。
因为x^2+y^2=n^2,变换一下,y^2=n^2-x^2=(n-x)(n+x)。
设gcd(n-x,n+x)=d,a=(n-x)/d,b=(n+x)/d,则有gcd(a,b)=1。
又由于y^2=a*b*d^2,且都是整数,则a*b是完全平方数。又因gcd(a,b)=1,所以a,b都是完全平方数。
设a=u^2,b=v^2(显然gcd(u,v)=1),则:n-x=d*u^2,n+x=d*v^2,两式相加得2n=d*(u^2+v^2)(显然u<v)。
那么,我们获得了关于u和v的约数条件:
1.u^2+v^2=n/d;
2.gcd(u,v)=1;
3.u<v;
那么,我们可以先通过O(sqrt(2n))的时间枚举d,然后通过sqrt(d)的时间枚举u,然后进行3个判断。时间复杂度约为O(2n^0.75)。
1 #include<bits/stdc++.h> 2 #define LL long long 3 using namespace std; 4 int n,ans; 5 int gcd(int x,int y){return y?gcd(y,x%y):x;} 6 void calc(LL oth){ 7 for (int u=1; u<=sqrt(oth); u++){ 8 int v=sqrt(oth-u*u); 9 if (u>=v) continue; 10 if (u*u+v*v!=oth) continue; 11 if (gcd(u,v)!=1) continue; 12 ans++; 13 } 14 } 15 int main(){ 16 scanf("%d",&n),ans=0; 17 for (int i=1; i<=sqrt((LL)n*2); i++) 18 if ((LL)n*2%i==0) calc(i),calc((LL)n*2/i); 19 printf("%d",ans*4+4); 20 return 0; 21 }
时间: 2024-10-04 09:51:01