思路:定义DP方程dp[i][j]标记选到第i个巧克力的时候,桌面上还剩下j个巧克力,状态转移有两个方向,dp[i-1][j-1],dp[i-1]lj+1],分别表示桌面上多了一个和消了一个,乘上需要的概率即可。
注意:这个题目的输入量很大,所以需要优化,首先是n+m是奇数的时候,或者m > c的时候概率是0。 然后就是当n很大的时候,可以知道后面所加的概率越来越小,题目要求精确到三位小数,所以大约1500以后的值就不会影响答案了,可以直接去掉。如果没有这两个优化,很容易超时。dp过程并不难,难得是时间上的优化(而且我的方法也并不好,跑了800ms)。
代码如下:
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> using namespace std; #define N 3000 double dp[N][N]; int main() { int c,n,m; double cc; while(~scanf("%d",&c)) { if(!c) break; scanf("%d%d",&n,&m); if(m > c || (m+n)%2){puts("0.000"); continue;} if(n > 1500){ n = 1500; } memset(dp,0,sizeof(dp)); dp[0][0] = 1.0; cc = c*1.0; for(int i = 1; i <= n; i++) { for(int j = 0; j <= c; j++) { if(j==0) dp[i][0] = dp[i-1][1]*(1/cc); else if(j==c) dp[i][c] = dp[i-1][c-1]*(1/cc); else { dp[i][j] += dp[i-1][j-1]*((c-j+1.0)/(c)); dp[i][j] += dp[i-1][j+1]*((j+1.0)/c); } } } printf("%.3lf\n",dp[n][m]); } return 0; }
时间: 2024-10-08 15:58:02