[快速幂][数学][dp] Jzoj P5813 计算
题解
- 令F(x)=∏(1<=i<=2m)xi,如果F(x)<n^m
- 令F(x')=∏(1<=i<=2m)n/xi,则F(x')>n^m
- 因为,F(x)*F(x')==n^2m,F(x)<n^m,所以F(x')>n^m
- 那么发现一个F(x)一定只对应一个F(x')
- 设F(x)<n^m有s1个,F(X)=n^m有s2个,F(X)>n^m有s3个
- 那么s1+s2+s3=为最后答案,那么s1=s3,所以只用求出s2的个数就好了
- 就转换为求F(X)=n^m的个数
- 现将n分解质因数n=p1^c1+p2^c2+...pk^ck
- n^m分解质因数就是p1^(c1*m)+p2^(c2*m)+...pk^(ck*m)
- 考虑就出对于每一个质因数的选数方案,再将它们乘起来就是所有的方案数了
- 考虑用dp求出选的方案数,设f[i][j]为选了i个数,sum是j的方案数
- f[i][j]=f[i][j]+f[i-1][j-k]
- j为枚举的当前的sum值0<=j<=ci*m
- k为枚举的转移的值0<=k<=min(ci,j)
代码
1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 #include <cstring> 5 #include <cmath> 6 using namespace std; 7 long long s2,f[210][210*100],mo=998244353,tot; 8 int n,m,k,num; 9 long long ksm(long long a,int b) 10 { 11 long long r=1; 12 for(;b;b>>=1,a=a*a%mo) if(b&1) r=r*a%mo; 13 return r; 14 } 15 void dp(int x) 16 { 17 memset(f,0,sizeof(f)); f[0][0]=1; 18 num=0; while (k%x==0) num++,k=k/x; 19 for (int i=1;i<=m*2;i++) 20 for (int j=0;j<=num*m;j++) 21 for (int z=0;z<=min(j,num);z++) 22 f[i][j]=(f[i][j]+f[i-1][j-z])%mo; 23 s2=(s2*f[m*2][num*m])%mo; 24 } 25 int main() 26 { 27 freopen("count.in","r",stdin); 28 freopen("count.out","w",stdout); 29 scanf("%d%d",&n,&m); 30 k=n; s2=1; 31 for (int i=1;i<=sqrt(n);i++) 32 if (n%i==0) 33 { 34 tot++; 35 if (i*i<n) tot++; 36 if (i>1&&k%i==0) dp(i); 37 } 38 if (k>1) dp(k); 39 printf("%lld",(ksm(tot,2*m)+s2)%mo*ksm(2,mo-2)%mo); 40 return 0; 41 }