lightoj1274
题意:题目看半天看不懂~。说白了,就是设yes为1,个数为n1;no为0,个数为n2,在最前面加上一个1,求相邻不同的期望。
题解
- dp[i][j][k]表示在第i个位置,前面(包括自身)有j个1,第i个位置为k相邻不同的期望。那么可以有两个转移,下一个为0或者1.
- p1表示为1的概率,p2表示为0的概率。最后求得是dp[0][0][1]。滚动数组优化一下。
代码
#include <bits/stdc++.h>
using namespace std;
int const N = 5000 + 10;
int n,s;
double dp[2][N][2];
int main(){
int T,caser = 0;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&s);
int yes = s - 2 * n, no = n - yes; //x表示YES,y表示NO
int cnt = 0;
memset(dp,0,sizeof(dp));
for(int i=n-1;i>=0;i--){
cnt ^= 1;
memset(dp[cnt],0,sizeof(dp[cnt]));
int MAX = min(yes,i), MIN = max(0,i-no); //表示yes的范围[MIN,MAX]
int down = n - i; //还可以选择的个数
for(int j=MIN;j<=MAX;j++){ //前i个位置中yes的个数
double p1 = 1.0 * (yes - j) / down, p2 = 1.0 * (no - (i - j)) / down;
dp[cnt][j][0] = (dp[cnt^1][j+1][1] + 1) * p1 + dp[cnt^1][j][0] * p2;
dp[cnt][j][1] = (dp[cnt^1][j][0] + 1) * p2 + dp[cnt^1][j+1][1] * p1;
}
}
printf("Case %d: %.6f\n",++caser,dp[cnt][0][1]);
}
return 0;
}