https://codeforces.com/contest/1097/problem/D
题意
给你一个n和k,问n经过k次操作之后留下的n的期望,每次操作n随机变成一个n的因数
题解
- 概率dp计算出每个素因子留下的概率,乘以这个素因子的值就是这个素因子的贡献期望
- 定义(dp[i][j])为第i次操作后剩下j个素因子的概率,概率dp顺着推
- (dp[i][j]->dp[i+1][k](k<=j))
- (dp[i+1][k]+=dp[i][j]frac{1}{j+1}(k<=j))
- (ans=sum^{cnt}_{i=1}sum^{num[i]}_{j=0}pr[i]^j*dp[k][j])
- 二维滚动数组滚掉一维
代码
#include<bits/stdc++.h>
#define P 1000000007
#define M 32000000
#define MAXN 100
#define ll long long
using namespace std;
ll dp[2][MAXN],inv[MAXN],n,ans=1;
int vi[M],sz,k,pr[M];
void sieve(){
inv[0]=inv[1]=1;
for(int i=2;i<MAXN;i++)inv[i]=(P-P/i)*inv[P%i]%P;
for(ll i=2;i<M;i++){
if(!vi[i])pr[++sz]=i;
for(int j=1;j<=sz&&pr[j]*i<M;j++){
vi[pr[j]*i]=1;
if(i%pr[j]==0)break;
}
}
}
int main(){
sieve();
cin>>n>>k;
for(int i=1;i<=sz&&pr[i]<=n;i++){
int cnt=0;
if(n%pr[i])continue;
while(n%pr[i]==0){
n/=pr[i];
cnt++;
}
memset(dp,0,sizeof(dp)); //
dp[0][cnt]=1;
int st=0;
for(int j=0;j<k;j++){
memset(dp[st^1],0,sizeof(dp[st^1]));
for(int p=0;p<=cnt;p++){
for(int q=0;q<=p;q++){
dp[st^1][q]+=dp[st][p]*inv[p+1]%P;
dp[st^1][q]%=P;
}
}
st^=1;
}
ll mul=1,tp=0;
for(int j=0;j<=cnt;j++){
tp+=dp[st][j]*mul%P;
tp%=P;
mul=mul*pr[i]%P;
}
ans=ans*tp%P; //
}
if(n>1){
memset(dp,0,sizeof(dp));
dp[0][1]=1;
int st=0;
for(int j=0;j<k;j++){
memset(dp[st^1],0,sizeof(dp[st^1]));
for(int p=0;p<=1;p++){
for(int q=0;q<=p;q++){
dp[st^1][q]+=dp[st][p]*inv[p+1]%P;
dp[st^1][q]%=P;
}
}
st^=1;
}
ll mul=1,tp=0;
for(int j=0;j<=1;j++){
tp+=dp[st][j]*mul%P;
tp%=P;
mul=mul*n%P;
}
ans=ans*tp%P;
}
cout<<ans;
}