1. 程式人生 > 實用技巧 >P2508 [HAOI2008]圓上的整點

P2508 [HAOI2008]圓上的整點

更好的閱讀體驗

題意:求半徑為\(r\)的圓上有多少個整點,即求\(x^2+y^2=r^2\)有多少組整數解。

我們考慮把\(r^2=x^2+y^2\)變形,得到\(r^2=x^2-(-y^2)=(x+yi)(x-yi)\)

所以我們就需要考慮通過分解\(r^2\)可以得到多少組不同的\((x+yi)(x-yi)\)

我們考慮如果有若干對共軛複數分別放在兩邊,最後得到的也是一對共軛複數,相乘就可以得到整數,我們希望這個整數是\(r\)

那麼就考慮如何求並分配這若干對共軛複數。

費馬平方和定理:奇素數 p 可以表示為兩個正整數的平方和,當且僅當 p 是 4 k+1 型的。並且在不考慮兩個正整數順序的情況下,這個表示方法唯一。

引入一個概念:高斯素數,即3,7這樣形似4 n+3的素數,他們一定不能被分成\((x+yi)(x-yi)\)的形式。

否則,如果是形似4 n+1的素數,一定能被分成\((x+yi)(x-yi)\)的形式。

那麼是否還忽略了某個素數呢?沒錯,2要特殊考慮,雖然它能被分成\(1^2+1^2=(1+i)(1-i)\),但特殊的是它所分解出的這兩個高斯整數的夾角還剛好是90度,這個要在計算答案的時候特殊考慮一下。

根據整數的惟一分解定理,我們可以讓\(r=p_1^{r_1}*p_2^{r_2}*...*p_k^{r_k}\)。考慮每個質因子對答案的影響。

如果這個因子不是高斯素數,也就是它能被分解成\((x+yi)(x-yi)\)

,假設它的冪次是\(m\),那麼我們可以得到\(m\)\(z:(a+bi)\)\(\overline z:(a-bi)\),考慮怎麼分配。我們可以在左邊分配\([0,m]\)\(z\),右邊分配剩下的\(z\),其他的就填\(\overline z\)。這樣它對答案的貢獻就是\(m+1\)

如果這個因子是高斯因數,也就是它不能被分解成\((x+yi)(x-yi)\),但是我們又一定要最後得到的等式兩邊共軛,所以只有當它的冪次\(m\)是偶數的時候,才能平均的分配到兩邊,否則就無解。

當然,我們也可以把\((x+yi),(x-yi)\)乘上\(-1,i,-i\)得到新的分解\((-x-yi),(-x+yi),(-y+xi),(y+xi),(y-xi),(-y-xi)\)

,所以我們還要把最後的答案乘上4.

等等,是不是忘了什麼?素數2還沒有在我們討論的範圍中。它可以分為\((1+i)(1-i)\),我們還是選擇放到兩邊,但是我們對它分解得到的兩個共軛複數來乘上\(-1,i,-i\),得到的分解是\((-1-i),(-1+i),(-1+i),(1+i),(1-i),(-1-i)\),我們可以發現這樣會得到重複的複數。

不妨在幾何中理解一下。

上面的乘上\(-1,i,-i\)其實就是把\((a+bi),(a-bi)\)兩個點旋轉起來,但是當這兩個點的夾角是90度的時候,這旋轉不能得到新的解,所以2對答案沒有影響。

所以最後的答案就是,將\(r^2\)進行質因數分解,一個高斯素數\(p^m\)若m是奇數,答案為0,否則不會對答案造成影響,一個非高斯素數\(p^m\)對答案的貢獻是\(m+1\),2忽略不計。

但是由於\(r^2\)裡的每一個質數的指數一定是偶數,所以答案不會為0。其他的就沒有問題了。

#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
   int x=0,f=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
   while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
   return x*f;
}
int ans(int n){
	int res=1;
	for(int i=2;i*i<=n;i++){
		if(n%i==0){
			int cnt=0;
			while(n%i==0)n/=i,cnt++;
			if(i%4==1)res*=(cnt<<1|1); 
		}
	}
	if(n!=1&&n%4==1)res*=(2+1);
	return res<<2;
}
signed main(){
	int n;
	cin>>n;
	cout<<ans(n)<<endl; 
	return 0;
}