卧薪尝胆,厚积薄发。
Check the difficulty of problems
Date: Thu Sep 06 19:04:21 CST 2018 In Category: NoCategory

Description:

给出队伍 $i$ 解决题目 $j$ 的概率 $p[i][j]$ ,求所有队伍都至少解决一题且冠军至少解决了 $k$ 道题的概率。
$1\le n \le 1000,1\le m \le 30$

Solution:

答案很不好算,考虑正难则反,用所有队伍都解决了一道题的概率 $P1$ 减去所有队伍解决的题目数都在 $[1,k-1]$ 之间的概率 $P2$ 。
设 $f[i][j][k]$ 表示第 $i$ 支队伍在前 $j$ 道题目中做出 $k$ 道的概率, $f[i][j][k] = f[i][j-1][k-1]\times p[i][j]+f[i][j - 1][k]\times(1 - p[i][j])$ .
$\begin{align}s[i][k]=\sum_{i=0}^mf[i][m][i]\end{align}$
$s[i][m]-s[i][0]$ 表示第 $i$ 支队伍至少做出一题的概率。
$s[i][k-1]-s[i][0]$ 表示第 $i$ 支队伍做出的题目在 $[1,k-1]$ 之间的概率。
其实就是前缀和。
$$\begin{align}P1=\prod_{i=1}^n(s[i][m] - s[i][0])\end{align}$ $
$$\begin{align}P2=\prod_{i=1}^n(s[i][k-1] - s[i][0])\end{align}$ $
最终结果 $$P=P1-P2$ $

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
int m,n,k;
#define MAXM 35
#define MAXN 1010
double p[MAXN][MAXM];
double f[MAXN][MAXM][MAXM];
double s[MAXN][MAXM];
int main()
{
while(scanf("%d%d%d",&m,&n,&k) && m != 0 && n != 0 && k != 0)
{
memset(f,0,sizeof(f));
memset(s,0,sizeof(s));
double P1 = 1,P2 = 1;
for(int i = 1;i <= n;++i)
for(int j = 1;j <= m;++j)
scanf("%lf",&p[i][j]);
for(int i = 1;i <= n;++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 > 0)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];
}
P1 = P1 * (s[i][m] - s[i][0]);
P2 = P2 * (s[i][k - 1] - s[i][0]);
}
printf("%.3lf\n",P1 - P2);
}
return 0;
}
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡