hdu2421 Deciphering Password

题意:求A^B的所有因子的因子数的三次方的和

语体教= =这题意实在太难表达了

因为肖学长的提示是质因数分解,所以直接想到的是分解A^B的质因数,B只是使所有质因数的个数乘B,所以就求A的质因数,接下来就晕了,总想要求A^B的所有因子数,或者用排列组合什么的

然后看了网上的题解,没想到直接跳过了求因子,直接求了因子的因子数的三次方和。

步骤:

1.打表求质数

2.求出A^B的每个质因子的个数cnt[i]

3.这步不好想,我是看网上推的公式然后理解了好半天。A^B的每个因子都是由A^B的质因子相乘得到的,组成一个新的因子m的时候,我们可以在A^B的每个质因子中选择0-cnt[i]个然后相乘

比如 A^B=40=2*2*2*5

cnt[2]=3 cnt[3]=0 cnt[5]=1

所以A^B的因子就是由这3个2 和一个5 组成,选择2时可以选0-4个,有4种选法,选择5时有0-1个,有两种选法,其他为0的都只有一种选法就是不选。

然后再看选出的这个因子m的因子数,假设m是由2个2和1个5组成,同样地可以选0-2个2,有三种选择,0-1个5两种选择,那么由m的质因子组成的因子数目,为3*2=6个

那么这个m的因子数的三次方就是((2+1)*(1+1))^3 枚举所有的选择 可以得出 ans=(1^3+2^3+……(cnt[0]+1)^3)*(1^3+2^3+……(cnt[1]+1)^3)*(1^3+2^3+……(cnt[2]+1)^3)*……(1^3+2^3+……(cnt[k]+1)^3)

就是从每个括号里各挑一个数组,乘积就是一个m的因子数的三次方了,假设从第i个括号里挑出的数为bi,那么b1*b2*……bk就表示现在这个因子是由(bi-1)个第i质因子组成的,那么再由这个因子组成新的因子时可以挑选0-(bi-1) bi种选法,这些bi的乘积就是现在这个因子的因子数了。

然后学会了一个公式:(1^3+2^3+……n^3)=(n*(n+1)/2)^2

数学渣。。大家勿喷= =

接下来就枚举m的质因子求上式乘积就好。


大体思路是这样,但是这个题卡时间,于是需要优化。

题目给的数据范围是1e6,但是没有必要打一个1-1e6的素数表,因为任何一个数n都最多只可能有一个质因子超过开平方后的n,也就是说,就算给你最大的数据范围1e6,它超过1000的质因子也只可能有一个(要不乘积就大于n了),而本题我们并不需要n的质因子的值,而只需要每个质因子的数量,于是,打一个范围1000的素数表,再用质因数分解的方式去分解n,如果n还有别的因子,那么cnt数组中只需要再加一个为1的质因子,时间优化了很多。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
__int64 prime[1010],a,b,num[1010];
int cnt,cnt_c;
bool isprime[1010];
void prepare()
{
	cnt=0;
	for(__int64 i=2;i<=1001;i++)
	{
		if(!isprime[i])
		{
			prime[cnt++]=i;
			for(__int64 j=i+i;j<=1001;j+=i)
			{	
				isprime[j]=1;
			}
		}
	}
	return;
}
int main()
{
	memset(isprime,0,sizeof(isprime));
	prepare();
	int c=0;
	while(scanf("%I64d%I64d",&a,&b)!=EOF)
	{
		cnt_c=0;
		for(int i=0;i<=cnt-1;i++)
		{
			if(a%prime[i]==0)  cnt_c++;
			if(a<prime[i]) break;
			while(a!=1&&a%prime[i]==0)
			{
				a/=prime[i];
				num[cnt_c-1]++;
			}
		}
		if(a!=1) num[cnt_c++]=1;
		__int64 ans=1,t=1;
		for(int i=0;i<=cnt_c-1;i++)
		{
			t=(((num[i]*b+1)%10007)*((num[i]*b+2)%10007)/2)%10007;
			t=(t*t)%10007;
			ans=(ans*t)%10007;
			num[i]=0;
		}
		printf("Case %d: %I64d\n",++c,ans);
	}
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值