题目大意
太长不想写qwq
题解
首先会发现,如果我们按照每一轮往后dp是行不通的,因为这样需要表示当前所有牌的选择状态。
于是我们令
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示前
i
i
i张牌中,
j
j
j张牌被选了的期望伤害是多少。然后我yy了一个递推式,调了一会儿发现这样行不通……因为第
i
i
i张牌的选择状态依赖于前面某些牌的选择状态。
既然后面依赖前面,那我们就反过来dp呗……
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示
i
i
i到
n
n
n中,有
j
j
j轮被占用的期望伤害是多少。注意这里
j
j
j不是多少牌被选择,因为可能有一轮什么牌都不选。
于是递推式就比较好办了,我们枚举当前的牌选或不选,如果选,在第几个被选。由于
i
i
i并不会影响
i
i
i之前的牌的选择,我们就可以大胆dp了。
f
[
i
]
[
j
]
=
(
1
−
p
[
i
]
)
j
f
[
i
+
1
]
[
j
]
+
∑
k
=
1
j
p
[
i
]
(
1
−
p
[
i
]
)
k
−
1
(
f
[
i
+
1
]
[
j
−
1
]
+
d
[
i
]
)
=
(
1
−
p
[
i
]
)
j
f
[
i
+
1
]
[
j
]
+
(
1
−
(
1
−
p
[
i
]
)
j
)
(
f
[
i
+
1
]
[
j
−
1
]
+
d
[
i
]
)
f[i][j]=(1-p[i])^jf[i+1][j]+\sum_{k=1}^jp[i](1-p[i])^{k-1}(f[i+1][j-1]+d[i])\\ =(1-p[i])^jf[i+1][j]+\left(1-(1-p[i])^j\right)(f[i+1][j-1]+d[i])
f[i][j]=(1−p[i])jf[i+1][j]+k=1∑jp[i](1−p[i])k−1(f[i+1][j−1]+d[i])=(1−p[i])jf[i+1][j]+(1−(1−p[i])j)(f[i+1][j−1]+d[i])
于是直接
O
(
n
r
)
O(nr)
O(nr)dp就没了。目前跑得飞快
#include <bits/stdc++.h>
using namespace std;
int T, n, r, d[225];
double f[225][135], p[225];
int main() {
for (scanf("%d", &T); T--;) {
scanf("%d%d", &n, &r);
for (int i = 1; i <= n; i++)
scanf("%lf%d", p + i, d + i);
for (int i = 0; i <= r; i++) f[n + 1][i] = 0;
for (int i = n; i > 0; i--) {
double mul = 1, pp = 1 - p[i];
for (int j = 1; j <= r; j++) {
mul *= pp;
f[i][j] = (1 - mul) * (f[i + 1][j - 1] + d[i]) + mul * f[i + 1][j];
}
}
printf("%.10lf\n", f[1][r]);
}
return 0;
}