太久没写题了,导致这题调半天。由于翻译插件坏了还读错题了一次。
容易想到先设 $dp_{i,j}$ 表示抽了前 $i$ 个,抽到 $j$ 张卡的概率,再设 $f_i=dp_{n,i}$ 表示一包卡中抽出 $i$ 张的概率。
然后就可以背包了,设 $g_i$ 表示获得 $i$ 张卡的期望抽卡次数,则可以枚举 $j$ 表示这次抽了多少:
$$g_i = 1 + \sum\limits_{j=0}^{n} g_{\max(0,i-j)} \times f_j$$
看上去很对,但是注意到 $j=0$ 的时候等号后面会有 $g_i$ 这一项。
所以考虑把 $j=0$ 单独提出来,转移方程变为:
$$g_i = 1 + \frac{1}{1 - f_0} ( \sum\limits_{j=1}^{n} g_{\max(0,i-j)} \times f_j )$$
#include <bits/stdc++.h>
using namespace std;
const int N = 5015;
int n, m, p[N];
long double dp[N][N], f[N], g[N], ans;
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) scanf("%d", &p[i]);
dp[0][0] = 1;
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= i; j++) {
dp[i][j] += dp[i - 1][j] * 1.00 * (100 - p[i]) / 100.00;
if (j) dp[i][j] += dp[i - 1][j - 1] * 1ll * p[i] / 100.00;
}
}
for (int i = 0; i <= n; i++) f[i] = dp[n][i];
// for (int i = 0; i <= n; i++) printf("%d %.5Lf\n", i, f[i]);
g[0] = 0;
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) g[i] += g[max(0, i - j)] * f[j];
g[i] = (g[i] + 1) * 1.00 / (1.00 - f[0]);
}
printf("%.15Lf\n", g[m]);
return 0;
}