BZOJ 1041: [HAOI2008]圆上的整点【高斯素数】
1041: [HAOI2008]圆上的整点
Time Limit: 10 Sec Memory Limit: 162 MB
Description
求一个给定的圆(x^2+y^2=r^2),在圆周上有多少个点的坐标是整数。
Input
只有一个正整数n,n<=2000 000 000
Output
整点个数
Sample Input
4
Sample Output
4
HINT
题解
我的想法和黄学长的想法不同,我没看懂他的想法QAQ。
我的想法比较神奇,因为看了这个视频,十分完美的解决了此题:https://www.bilibili.com/video/av12131743/,讨论里也有,就是科普视频的完整版(我也不知道BZOJ里为什么只能看5分钟)。
视频有点长,但是我还是建议看一下,十分有帮助。
我继续视频中讲到的知识,解决这道题。
显然是要将拆成素数的积,但是题目给的是半径。
所以我们要求的素数积。
那么怎么求呢?
所以只需要求r的质因子然后就可以了。
然后我们要求
对于,没有任何质因子只出现奇数次的情况,所以只需要判的情况,直接就可以了。
当然,我们求r,所以只需要筛到就可以了,但是有情况是r本身是一个大素数,或是一个大素数*小素数,所以晒完之后再特判一下就可以了。
代码如下
#include<cmath>
#include<cstdio>
#define LL long long
using namespace std;
LL n,m,Ans=1,p[500005];
bool vis[500005];
void make_p(){
int Len=500000;
vis[0]=vis[1]=1;
for(int i=2;i<=Len;i++){
if(!vis[i]) p[++p[0]]=i;
for(int j=1;j<=p[0]&&i*p[j]<=Len;j++){
vis[i*p[j]]=1;
if(!(i%p[j])) break;
}
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("prob.in","r",stdin);
freopen("prob.out","w",stdout);
#endif
make_p();
scanf("%lld",&n);
while(!(n&1)) n/=2;
for(int i=1;i<=p[0]&&p[i]<=n;i++)
if(!(n%p[i])){
LL Num=0;
while(!(n%p[i])) Num++,n/=p[i];
Num<<=1;
if(p[i]%4==1) Ans*=Num+1;
}
if(n>1) if(n%4==1) Ans*=3;
printf("%lld\n",Ans*4);
return 0;
}