【BZOJ】【1041】【HAOI2008】圆周上的点
数学
orz hzwer
完全不会做……
很纠结啊,如果将来再遇到这种题,还是很难下手啊……
引用题解:
【分析】:
样例图示:
首先,最暴力的算法显而易见:枚举x轴上的每个点,带入圆的方程,检查是否算出的值是否为整点,这样的枚举量为2*N,显然过不了全点。
然后想数学方法。
有了上面的推理,那么实现的方法为:
枚举d∈[1,sqrt(2R)],然后根据上述推理可知:必先判d是否为2R的一约数。
此时d为2R的约数有两种情况:d=d或d=2R/d。
第一种情况:d=2R/d。枚举a∈[1,sqrt(2R/2d)] <由2*a*a < 2*R/d转变来>,算出对应的b=sqrt(2R/d-a^2),检查是否此时的A,B满足:A≠B且A,B互质 <根据上面的推理可知必需满足此条件>,若是就将答案加1
第二种情况:d=d。枚举a∈[1,sqrt(d/2)] <由2*a*a < d转变来>,算出对应的b=sqrt(d-a^2),检查是否此时的A,B满足:A≠B且A,B互质 <根据上面的推理可知必需满足此条件>,若是就将答案加1
因为这样只算出了第一象限的情况<上面枚举时均是从1开始枚举>,根据圆的对称性,其他象限的整点数与第一象限中的整点数相同,最后,在象限轴上的4个整点未算,加上即可,那么最后答案为ans=4*第一象限整点数+4
【时间复杂度分析】:
枚举d:O(sqrt(2R)),然后两次枚举a:O(sqrt(d/2))+O(sqrt(R/d)),求最大公约数:O(logN)
1 /************************************************************** 2 Problem: 1041 3 User: Tunix 4 Language: C++ 5 Result: Accepted 6 Time:192 ms 7 Memory:816 kb 8 ****************************************************************/ 9 10 //BZOJ 1000 11 #include<cmath> 12 #include<cstdio> 13 using namespace std; 14 typedef long long LL; 15 typedef double lf; 16 /******************tamplate*********************/ 17 LL r,ans; 18 LL gcd(LL x,LL y){return y?gcd(y,x%y):x;} 19 bool check(LL y,lf x){ 20 if (x==floor(x)){ 21 LL x1=x; 22 if (gcd(x1*x1,y*y)==1 && x1*x1!=y*y) 23 return 1; 24 } 25 return false; 26 } 27 int main(){ 28 scanf("%lld",&r); 29 for(LL d=1;d<=sqrt(2*r);d++) 30 if (2*r%d==0){ 31 for(LL a=1;a<=(LL)sqrt(2*r/(2*d));a++){ 32 lf b=sqrt((2*r)/d-a*a); 33 if (check(a,b))ans++; 34 } 35 if (d!=2*r/d){ 36 for(LL a=1;a<=(LL)sqrt(d/2);a++){ 37 lf b=sqrt(d-a*a); 38 if (check(a,b))ans++; 39 } 40 } 41 } 42 printf("%lld\n",ans*4+4); 43 return 0; 44 }
1041: [HAOI2008]圆上的整点
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2376 Solved: 1019
[Submit][Status][Discuss]
Description
求一个给定的圆(x^2+y^2=r^2),在圆周上有多少个点的坐标是整数。
Input
r
Output
整点个数
Sample Input
4
Sample Output
4
HINT
n<=2000 000 000