[BZOJ1041][HAOI2008] 圆上的整点
给定一个圆 x2+y2=r2,r 为整数 ,求在圆周上有多少个点的坐标是整数。
n≤2×108
其实这不是计算几何,而是数论。
x2+y2=r2⟹y=(r+x)(r−x)‾‾‾‾‾‾‾‾‾‾‾‾√
令 d=gcd(r+x,r−x), 设 A=r−xd,B=r+xd
则 gcd(A,B)=1, 即 A,B 互质.
回带得 y2=d2⋅A⋅B
由于 d2,y2 为完全平方数 , 则 A⋅B 为完全平方数;
又 gcd(A,B)=1, 排除 A=B 的情况 , 说明 A,B 均为完全平方数.
设 A=a2,B=b2
则
a2=r−xd,b2=r+xd⟹a2+b2=2rd
观察可知: d 为
具体统计的思路是枚举可能的 a,b 看是否满足 gcd(A,B)=1.
我们先枚举 d∈[1,2r‾‾√],d∣2r;
然后对于每一个满足条件的 d 我们就找到了两个约数
- 枚举 a∈[1,rd‾‾√] (不妨设 a<b ,则 2a2≤2rd) ,则 b=2rd−a2‾‾‾‾‾‾‾‾√ ,判断并统计答案;
- 枚举 a∈[1,d2‾‾√] (2a2≤d), 则 b=d−a2‾‾‾‾‾‾√, 判断并更新答案.
那么我们已经求出了一个象限的圆上整点数 res 了,根据圆的对称性,再统计上坐标轴上的 4 个整点,答案就是
#include<iostream>
#include<cstdio>
#include<cmath>
typedef long long ll;
ll R,ans=0;
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
bool check(ll y,double x)
{
if(x==std::floor(x))
{
ll x1=(ll)floor(x);
if(gcd(x1*x1,y*y)==1&&x1*x1!=y*y)
return true;
}
return false;
}
int main()
{
scanf("%lld",&R);
for(ll d=1;d*d<2*R;d++)
if((2*R)%d==0)
{
for(ll a=1;a*a<=2*R/(2*d);a++)
{
double b=std::sqrt(2*R/d-a*a);
if(check(a,b)) ans++;
}
if(d!=2*R/d)
for(ll a=1;a*a<=d/2;a++)
{
double b=sqrt(d-a*a);
if(check(a,b)) ans++;
}
}
printf("%lld\n",ans*4+4);
return 0;
}