xdoj 1243 ckj老师爱数学

题目链接:

xdoj 1243 ckj老师爱数学 传送门

大致题意是已知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;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值