题目链接:
大致题意是已知z,求满足x^2+y^2=z^2的整数解x,y的个数。这道题是在暑期集训结束的组队赛碰到的,原题貌似是BZOJ上求半径为r的圆上整点的个数。
乍一看题,卧槽z的范围怎么那么大,暴力肯定要超时的啊!然后就开始暴力打表找规律= =。。。
想知道正解的话建议去搜BZOJ原题的题解,这里只有我打表找到规律的做法(正解我也不会2333)。
博主首先直接暴力打出了z从1开始到100+左右的表,观察规律。当然这个规律并不算很明显,至少博主是看了很久的。最开始发现,答案为12时的z都是4的倍数+1且为质数,而这些质数的倍数貌似也满足某种规律?然后就实验了很多组数据,首先验证了4的倍数+1且为质数的z的答案都是12。然后以该类数为基础,推断出这些数的倍数与这些数所具有的联系,最后总结出整体的规律。(这种做法真的挺乱搞的,全靠人品、YY和找规律= =)
1、当z为0时,答案为1,z为1时,答案为4。
2、z不为1时,将z分解为质因数的幂相乘的形式,p[]数组存质因数,对应的e[]数组存幂次。
若z没有%4余1的质因数,则答案为4,若z含有若干个%4余1的质因数,对于每一个p都有(2*e+1)个4,将所有符合条件(%4余1)的质数的(2*e+1)乘起来,最后所得的结果再乘以4即为答案。(可能表述的不是很清楚,看代码吧)
另外,比赛时分解的时候板子敲错了,但是数据不怎么强,居然过了。当然赛后不久发现了,略一修改成功过了BZOJ原题,想来虽不是正解,这样写也是可以的。
AC代码如下:(对于质数来说,显然直接判断要比分解来得快,所以直接可以输出答案)
#include
#include
#include
#include
#include
using namespace std;
#define N 1000010
int cnt1,cnt2,prime[N],p[100],e[100],ans[100];
bool notprime[N];
void init(){
cnt1=0;
notprime[1]=1;
for(int i=2;i<N;i++){
if(notprime[i]==false)
prime[cnt1++]=i;
for(int j=0;j<cnt1&&prime[j]*i<N;j++){
notprime[prime[j]*i]=true;
if(i%prime[j]==0){
break;
}
}
}
}
void fenjie(int n){
cnt2=0;
memset(p,0,sizeof(p));
memset(e,0,sizeof(e));
for(int i=0;i<cnt1&&prime[i]<=n;i++){
if(n%prime[i]==0){
p[cnt2]=prime[i];
while(n%prime[i]==0){
n/=prime[i],e[cnt2]++;
}
cnt2++;
}
}
if(n>1){
p[cnt2]=n,e[cnt2++]=1;
}
}
bool isprime(int n){
if(n==1)
return false;
for(int i=2;i<=sqrt(n);i++){
if(n%i==0)
return false;
}
return true;
}
int main(){
init();
int t;
scanf("%d",&t);
while(t--){
int n;
scanf("%d",&n);
if(n==1){
printf("1\n");
continue;
}
bool c=isprime(n);
if(n%4==1&&c){
printf("12\n");
}
else if(c){
printf("4\n");
}
else{
fenjie(n);
int s=1;
memset(ans,0,sizeof(ans));
for(int i=0;i<cnt2;i++){
if(p[i]%4==1){
ans[i]=e[i]*2+1;
s*=ans[i];
}
}
if(s==0)
printf("4\n");
else
printf("%d\n",s*4);
}
}
return 0;
}