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