1. 程式人生 > >BZOJ 1041 圓上的整點 數論

BZOJ 1041 圓上的整點 數論

題意:給出R,問半徑為R的圓上有多少個整數點? R<=2e9.


x^2+y^2=r^2.  -> (r+x)(r-x)=y^2 . 令d=gcd(r+x,r-x).m=(r+x)/d,n=(r-x)/d.
則y^2= d^2*m*n . 因為gcd(m,n)=1 所以m,n都為完全平方數.(m,n素因子分解後的冪都為偶數.)
那麼讓m=u^2,n=v^2.  得:r+x=d*u^2,r-x=d*v^2. 相加後得: 2r=d(u^2+v^2).


d為2r的約束. Sqrt(2r)內列舉d 然後在Sqrt(2r/d)內列舉u即可.得到(u,v,d)就能確定一組(x,y) .注意gcd(u,v)=1.

因為上面算的只是第一象限內的點.答案乘4後+4個座標軸上的點即可.

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5;
ll R;
ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
int main()
{
	cin>>R;
	R*=2;
	ll res=0;
	for(ll i=1;i*i<=R;i++)
	{
		if(R%i)	continue;
		ll t=R/i;
		for(ll u=1;u*u<=t;u++)
		{
			ll v=sqrt(t-u*u);
			if(v<=u)	break;
			if(v*v+u*u!=t)	continue;
			if(gcd(u,v)==1)	res++;
		}
		if(i*i==R)	break;
		t=i;
		for(ll u=1;u*u<=t;u++)
		{
			ll v=sqrt(t-u*u);
			if(v<=u)	break;
			if(v*v+u*u!=t)	continue;
			if(gcd(u,v)==1)	res++;
		}
	}	
	res*=4;
	res+=4;
	cout<<res<<'\n';
	return 0;
}

mark

圓上的整數點(a,b)滿足 a^2+b^2=R^2.

等價於在複平面上有多少個z=a+bi 滿足(a+bi)*(a-bi)=a^2+b^2 =R^2


先將R做素因子分解.R^2=p1^q1 * ...pk^qk.
若p mod 4 = 1 那麼它可以拆成一組共軛高斯素數相乘.
若p mod 4 = 3 那麼這個p不能被拆分.

每個p拆分成(a+bi)*(a-bi) 分成左右兩列.分別放互為共軛的複數. 
最後兩列結果分別為(A+Bi)(A-Bi). A^2+B^2=R^2.

總共選法為4*(q1+1)*...(qk+1). qi都為mod4==1的素數. 4為複數乘上1,-1,i,-i.