Hello 2019 D 素因子貢獻法計算期望 + 概率dp + 滾動數組
阿新 • • 發佈:2019-05-03
ans 概率dp pro clas https continue http 素因子 操作
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; }
Hello 2019 D 素因子貢獻法計算期望 + 概率dp + 滾動數組