题意:一开始所有n个硬币都是反面朝上的,每次必须拿k个来抛,抛的人足够聪明,问m次之后向上的硬币的期望。
首先说了这个足够聪明的意思,就是只要向反面的有k个就不会sb地去拿向正面的来抛,想了一会之后就觉得是个概率dp的转移,
然而一开始想漏了个组合数的加权,但在+1的提醒下搞通了,但是分析了下,这是nmk的时间复杂度,
1e6还有个1e3的大T,emmm理论上会TLE的,但结果看网上题解,都是跟自己思路差不多,所以也是很迷。
嗯,转移过程其实很简单,dp[i][j]就是第i次抛了之后j个硬币向上的概率,所以如果n-j>=k很明显,这是全部拿向反面的来抛就行,那么dp[i+1][j+kk]=dp[i][j]*0.5的k次方*k个里面有kk个向正面的组合数
而n-j<的话,那么就得那一些向正面的来抛了,剩下的正面的就j-(k-(n-j))也就是n-k个,那么dp[i+1][n-k+kk]=dp[i][j]*0.5的k次方*k个里面有kk个向正面的组合数
1 #include<cstdio> 2 const int N=111; 3 double cf05[N],c[N][N],dp[N][N]; 4 void init(){ 5 for(int i=0;i<=100;i++){ 6 c[i][0]=1.0; 7 for(int j=1;j<=i;j++){ 8 if(j<=i/2) c[i][j]=c[i-1][j-1]+c[i-1][j]; 9 else c[i][j]=c[i][i-j]; 10 } 11 } 12 cf05[0]=1.0; 13 for(int i=1;i<=100;i++) cf05[i]=cf05[i-1]*0.5; 14 } 15 int main(){ 16 init(); 17 int t,n,m,k; 18 scanf("%d",&t); 19 while(t--){ 20 scanf("%d%d%d",&n,&m,&k); 21 for(int i=0;i<=m;i++) 22 for(int j=0;j<=n;j++) dp[i][j]=0.0; 23 dp[0][0]=1.0; 24 for(int i=0;i<m;i++){ 25 for(int j=0;j<=n;j++){ 26 if(dp[i][j]==0.0) continue; 27 for(int kk=0;kk<=k;kk++){ 28 if(n-j>=k) dp[i+1][j+kk]+=dp[i][j]*cf05[k]*c[k][kk]; 29 else dp[i+1][n-k+kk]+=dp[i][j]*cf05[k]*c[k][kk]; 30 } 31 } 32 } 33 double ans=0.0; 34 for(int i=0;i<=n;i++) ans+=dp[m][i]*i; 35 printf("%.3f\n",ans); 36 } 37 return 0; 38 }
怪怪的哦
原文地址:https://www.cnblogs.com/LMCC1108/p/11638497.html
时间: 2024-11-13 15:06:30