hdu2421 Deciphering Password

来源:互联网 发布:linux查看gitlab版本 编辑:程序博客网 时间:2024/06/03 10:12

题意:求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 0