//题意:给你一个M,T,N, 分别代表题的总数,几只队伍,做题最多的队伍最少要做的题数量可以大于N(当然不止一个队伍),题目要求输出,所有队伍至少作对一道且有队伍至少作对N道的概率。样例中的弟i行代表弟i只队伍分别做M个题作对的概率
//思路:分析一下,设至少作对一道的概率为p已知,那么此题实际就是求作对N道的概率。然而对于作对N道题直接求该怎么求呢?首先对于每只队伍做每道题作对的概率我们已知,那么首先我们求出p。对于每个队伍如果一道题都做不出来的概率很好求设为p1,那么p = 1-p1,所有的p相乘就是所有的 队伍至少做出一道的概率p;为了求p这里我们设p[i][j]表示弟i只队伍做弟j道题的概率。用dp的思想我们设f[i][j][k]表示第i只队伍做前j道题对k道题的概率那么所有的f[i][m][0]相乘就是p1.但是如果这么做有个难点是至少做N道不好求,我们不妨在设一个变量数组s[i][j]表示第i只队伍最多作对j道题的概率,那么p就相当与所有的1-s[i][0]想乘。而此时对于至少作对N道题可以转化为:设q为最多做对n-1道,那么此题实际求的概率就是p-q。
【注意】:这里用double提交过不去,我下去仔细查了一下double与float的区别、精度以及范围,没想懂为什么。
//7324K 79MS
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxt=1010,maxm=40;
float f[maxt][maxm][maxm],s[maxt][maxm],p[maxt][maxm];
int main()
{
int m, t, n;
while(scanf("%d%d%d", &m, &t, &n) != EOF && m && n && t){
for(int i = 1; i <= t; i++){
for(int j = 1; j <= m; j++){
scanf("%f", &p[i][j]);
}
}
memset(f, 0, sizeof(f));
for(int i = 1; i <= t; i++){
f[i][0][0] = 1;
for(int j = 1; j <= m; j++){
for(int k = 0; k <= j; k++){
f[i][j][k] = f[i][j-1][k] * (1 - p[i][j]);
if(k)
f[i][j][k] += f[i][j-1][k-1] * p[i][j];
}
}
s[i][0] = f[i][m][0];
for(int j = 1; j <= m; j++){
s[i][j] = s[i][j-1] + f[i][m][j];
}
}
float p1 = 1, p2 = 1;
for(int i = 1; i <= t; i++){
p1 *= (1 - s[i][0]);
p2 *= (s[i][n-1] - s[i][0]);
}
printf("%.3f\n", p1-p2);
}
return 0;
}