守卫挑战
题目链接:ybt金牌导航1-1-9
题目大意
有一些任务,每个任务有一定的几率可以成功。
成功会让一个初始为 K 的数加一个值。(不同的任务减去的值不同,会有 -1 和正整数)
然后要你在保证至少成功 L 次的情况下,最后这个值是非负数的概率。
思路
这道题的数据较小,考虑直接普通的 dp 概率。
然后虽然
K
K
K 可以到
2000
2000
2000,但是可以当做
200
200
200 来看。(反正两个都不会爆空间、影响结果,这样还能把
K
K
K 变成
200
200
200)也就是说,当任何一个时候
K
K
K 值大于
200
200
200 的时候,你都可以把它变成
200
200
200。(当然,负就是到
−
200
-200
−200)
那我们很容易设
f
i
,
j
,
k
f_{i,j,k}
fi,j,k 为前
i
i
i 个任务中成功了
j
j
j 个,现在
K
K
K 值是
k
k
k 的概率。
那得到转移也很容易想到:
{
f
i
,
j
,
k
+
a
i
=
f
i
−
1
,
j
,
k
+
a
i
×
(
1.0
−
p
i
)
(
j
=
0
)
f
i
,
j
,
k
+
a
i
=
f
i
−
1
,
j
,
k
+
a
i
×
(
1.0
−
p
i
)
+
f
i
−
1
,
j
−
1
,
k
×
p
i
(
j
>
0
)
\left\{\begin{matrix} f_{i,j,k+a_i}=f_{i-1,j,k+a_i}\times (1.0 - p_i)&(j=0)\\ f_{i,j,k+a_i}=f_{i-1,j,k+a_i}\times (1.0 - p_i)+f_{i-1,j-1,k}\times p_i&(j>0) \end{matrix}\right.
{fi,j,k+ai=fi−1,j,k+ai×(1.0−pi)fi,j,k+ai=fi−1,j,k+ai×(1.0−pi)+fi−1,j−1,k×pi(j=0)(j>0)
当然,要记得
k
k
k 值要与
200
200
200 取最小值。
而且你会发现
k
k
k 的范围是
−
200
∼
200
-200\sim200
−200∼200,那就要把所有的
k
k
k 都加
200
200
200(都变成非负的,才可以放在数组里),而且去最小值的时候就是跟
400
400
400 比了。
至于初始化,根据上面要把
k
k
k 加
200
200
200,原来应该是
f
0
,
0
,
K
=
1
f_{0,0,K}=1
f0,0,K=1 的就变成了
f
0
,
0
,
K
+
200
=
1
f_{0,0,K+200} = 1
f0,0,K+200=1。
(一开始
k
k
k 是
K
K
K 是因为一开始的
K
K
K 就是这个值)
然后 dp 完之后,我们看看怎么统计答案。
很容易想到,我们枚举最后任务成功的数量
i
i
i,范围是
L
∼
n
L\sim n
L∼n,然后在枚举最后
K
K
K 的值
j
j
j,范围是
0
∼
200
(
+
200
)
0\sim200(+200)
0∼200(+200),然后所有的
f
n
,
i
,
j
f_{n,i,j}
fn,i,j 相加就是我们要的答案了。
代码
#include<cstdio>
#include<iostream>
#define bp_add 200
using namespace std;
int n, l, K, a[201];
double p[201], f[201][201][402], ans;
int main() {
scanf("%d %d %d", &n, &l, &K);
for (int i = 1; i <= n; i++) {
scanf("%lf", &p[i]);
p[i] /= 100.0;
}
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
f[0][0][K + bp_add] = 1.0;
for (int i = 1; i <= n; i++)
for (int j = 0; j <= i; j++)
for (int k = -200; k <= 200; k++) {
f[i][j][min(400, k + bp_add + a[i])] = f[i - 1][j][min(400, k + bp_add + a[i])] * (1.0 - p[i]);
if (j) {
f[i][j][min(400, k + bp_add + a[i])] += f[i - 1][j - 1][min(400, k + bp_add)] * p[i];
}
}
for (int i = l; i <= n; i++)
for (int j = bp_add + 0; j <= 200 + bp_add; j++)
ans += f[n][i][j];
printf("%.6lf", ans);
return 0;
}