Codeforces Round #284 (Div. 1) B. Name That Tune(概率DP)(难)
大致题意:听歌识曲,有n首歌,每首歌有ti的时间供你猜,当到ti时就会播放歌曲名所以必定会猜中,除了ti秒以外,其它每s猜中的概率是p,求Ts后猜中的歌曲个数的期望
我们设dp[i][j]表示猜到第i首歌,所用时间恰好为j的概率。
如果第i首歌识别的概率是pi。最多所用次数为ti。
如今我们识别第i首歌所用总时间恰好为j,那么其可能是dp[i-1][j-ti],dp[i-1][j-ti+1],......,dp[i-1][j-1]转移过来的。
显然暴力dp的复杂度是O(n^3)会T,所以进一步优化,dp[i][j]可由dp[i][j-1] O(1)推得
期望等于每首歌被猜中的概率之和
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #include<cmath> using namespace std; const int N =5e3+100; int n,T; double dp[N][N]; double p[N]; int t[N]; int main() { cin>>n>>T; for(int i=1;i<=n;i++) cin>>p[i],p[i]=p[i]/100,cin>>t[i]; dp[0][0]=1; double ans=0; for(int i=0;i<=n;i++) { double pp1,pp2; if(i>0&&t[i]>2) pp1=pow(1-p[i],1.0*(t[i]-2)); pp2=pow(1-p[i+1],t[i+1]-1); for(int j=0;j<=T;j++) { if(dp[i][j]==0) continue; if(i>0&&t[i]>2) { double tmp=dp[i][j]; if(j>=t[i]) tmp-=dp[i-1][j-t[i]]*pp1*(1-p[i]); if(j>=t[i]-1) tmp-=dp[i-1][j-t[i]+1]*pp1*p[i]; dp[i][j+1]+=tmp*(1-p[i]); } if(j+1<=T&&t[i+1]>1) dp[i+1][j+1]+=dp[i][j]*p[i+1]; if(j+t[i+1]<=T)dp[i+1][j+t[i+1]]+=dp[i][j]*pp2; if(i>0) ans+=dp[i][j]; } } printf("%.10f\n",ans); }