BZOJ1041 [HAOI2008]圆上的整点 【数学】
1041: [HAOI2008]圆上的整点
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 4631 Solved: 2087
[Submit][Status][Discuss]
Description
求一个给定的圆(x^2+y^2=r^2),在圆周上有多少个点的坐标是整数。
Input
只有一个正整数n,n<=2000 000 000
Output
整点个数
Sample Input
4
Sample Output
4
最容易想到的就是直接枚举O(n ^2)
思考如何简化:尽量减少不必要的枚举
我们观察y = sqrt(r^2 - x^2) = sqrt((r + x) * (r - x))
我们令d = gcd(r + x,r - x),则(r + x) * (r - x) = d^2 * ((r + x)/d) * ((r - x)/d)
又因为y = sqrt((r + x) * (r - x)),所以其必定为完全平方数,又因为(r + x)/d与(r - x)/d互质,所以它们也是完全平方数
我们令d * u^2 = r - x,d * v^2 = r + x
两式联立得:2r/d = u^2 + v^2,x = (v^2 - u^2) * d / 2,y = d*u*v
由此我们得出u与v的限制:①gcd(u,v)=1 ②u^2 + v^2 = 2r/d ③u <v
如果条件满足,就对应第一象限的一组解,总的解为 4 * ans + 4
时间复杂度分析:
第一层枚举O(√(2n)),第二层枚举O(√(2n/d))
而一个数的总的O(n/k)比O(n)小很多很多,完全可以接受
#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #define LL long long int #define eps 1e-9 #define REP(i,n) for (int i = 1; i <= (n); i++) using namespace std; const int maxn = 100005,maxm = 100005,INF = 1000000000; LL n,ans = 0; inline int gcd(int a,int b){return !b ? a : gcd(b,a % b);} void check(LL d){ LL R = 2 * n / d,E = (LL)sqrt(R),v; for (int i = 1; i < E; i++){ v = (LL)sqrt(R - i * i); if (gcd(i,v) == 1 && i <= v &&i * i + v * v == R) ans++; } } int main() { cin >> n; LL E = (LL)sqrt(2.0 * n); for (int i = 1; i <= E; i++){ if (2 * n % i) continue; if (i * i == 2 * n) check(i); else check(i),check(2 * n / i); } cout<<4 * ans + 4<<endl; return 0; }