题目链接:
http://poj.org/problem?id=2151
题意:
题目中有
T
T
T个人,
M
M
M道题,做出最多题数要大于等于
N
N
N,给你一个
p
p
p矩阵,
p
[
i
]
[
j
]
p[i][j]
p[i][j]表示第
i
i
i个人写出第
j
j
j题的概率。
现求满足每个人写题数量都至少大于等于1并且做题数量最多的人写题数量大于N的概率。
题解:
设
T
T
T为全部人的一个集合,
f
(
t
)
f(t)
f(t) 为
t
t
t 这个人的写题数量。
那么题目可以表述为:求满足任意
t
∈
T
t∈T
t∈T,都有
f
(
t
)
>
=
1
f(t) >= 1
f(t)>=1且存在
t
0
∈
T
t_0∈T
t0∈T,使得
f
(
t
0
)
>
=
N
f(t_0)>=N
f(t0)>=N的概率。
设使得条件1成立的概率为
p
1
p_1
p1,
使得条件2成立的概率为
p
2
p_2
p2,
条件3为任意
t
∈
T
t∈T
t∈T,都有
f
(
t
)
<
N
f(t) < N
f(t)<N,其概率记做
p
3
p_3
p3,
其中条件2和3互逆,所以有
p
=
p
1
∗
(
1
−
p
3
)
=
p
1
−
p
1
∗
p
3
p = p_1 * (1 - p_3) = p_1 - p_1 * p_3
p=p1∗(1−p3)=p1−p1∗p3。
那么现在就只用求
p
r
e
[
i
]
[
j
]
pre[i][j]
pre[i][j],即第
i
i
i人做题数量小于
j
j
j的概率
最后答案就是
p
1
−
p
1
∗
p
3
=
∏
i
=
1
T
(
1
−
p
r
e
[
i
]
[
0
]
)
−
∏
i
=
1
T
(
p
r
e
[
i
]
[
N
−
1
]
−
p
r
e
[
i
]
[
0
]
)
p_1 - p_1 * p_3 = \prod_{i=1}^{T} (1 - pre[i][0]) - \prod_{i = 1}^{T}(pre[i][N - 1] - pre[i][0])
p1−p1∗p3=∏i=1T(1−pre[i][0])−∏i=1T(pre[i][N−1]−pre[i][0])。
而在求答案的过程中,要先求出第
i
i
i个人写出
j
j
j题的概率才能求出
p
r
e
[
i
]
[
j
]
pre[i][j]
pre[i][j]。
记
f
[
j
]
[
k
]
f[j][k]
f[j][k]为第
i
i
i个人在写第
j
j
j题,要做出
k
k
k题的概率,其中
f
[
1
]
[
0
]
=
1
−
p
[
i
]
[
j
]
f[1][0] = 1 - p[i][j]
f[1][0]=1−p[i][j],
f
[
1
]
[
1
]
=
p
[
i
]
[
j
]
f[1][1] = p[i][j]
f[1][1]=p[i][j]
转移方程为
j
>
1
时
,
f
[
j
]
[
k
]
=
当
前
这
题
做
出
来
+
当
前
这
题
没
做
出
来
=
p
[
i
]
[
j
]
∗
f
[
j
−
1
]
[
k
−
1
]
+
(
1.0
−
p
[
i
]
[
j
]
)
∗
f
[
j
−
1
]
[
k
]
j > 1时, f[j][k] = 当前这题做出来 + 当前这题没做出来 = p[i][j] * f[j - 1][k - 1] + (1.0 - p[i][j]) * f[j - 1][k]
j>1时,f[j][k]=当前这题做出来+当前这题没做出来=p[i][j]∗f[j−1][k−1]+(1.0−p[i][j])∗f[j−1][k]
j
=
0
时
,
f
[
j
]
[
k
]
=
当
前
这
题
没
做
出
来
=
(
1.0
−
p
[
i
]
[
j
]
)
∗
f
[
j
−
1
]
[
k
]
j = 0时, f[j][k] = 当前这题没做出来 = (1.0 - p[i][j]) * f[j - 1][k]
j=0时,f[j][k]=当前这题没做出来=(1.0−p[i][j])∗f[j−1][k]
代码:
const int MAX = 1e3 + 10;
int M, T, N;
double f[MAX][MAX];//当前做第k题,做前i题能写出j题概率
double pre[MAX];//第i人写出题目数量小于等于j题概率
int main() {
while (~scanf("%d%d%d", &M, &T, &N)) {//题数,人数,最多题数最小值
if (M == 0 && N == 0 && T == 0)break;
double p1 = 1.0, p2 = 1.0;
for (int i = 1; i <= T; i++) {//第i人
double p;
scanf("%lf", &p);
f[1][0] = 1.0 - p, f[1][1] = p;
for (int j = 2; j <= M; j++) {//当前第j题
scanf("%lf", &p);
f[j][0] = (1.0 - p) * f[j - 1][0];
for (int k = 1; k <= j; k++)//要做k题
f[j][k] = p * f[j - 1][k - 1] + (1.0 - p) * f[j - 1][k];
}
pre[0] = f[M][0];//一题没做出来
for (int j = 1; j <= N - 1; j++)
pre[j] = pre[j - 1] + f[M][j];
p1 *= 1.0 - pre[0];//至少做了一题
p2 *= pre[N - 1] - pre[0];//做题数量在[1, N - 1]
}
printf("%.3lf\n", p1 - p2);
}
return 0;
}