BZOJ1041 [HAOI2008]圆上的整点 【数学】

1041: [HAOI2008]圆上的整点

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 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;
}


posted @ 2017-11-26 14:20  Mychael  阅读(168)  评论(0编辑  收藏  举报