【YBTOJ】守衛挑戰
阿新 • • 發佈:2021-01-20
題目大意:
有 \(n\) 項任務,有一個數 \(K\)。每一項任務成功的概率是 \(p_i\)(這裡與原題目不同,原題目是百分之 \(p'_i\),這裡相當於 \(p_i=\frac{p'_i}{100}\)),成功後會使 \(K\) 加上 \(a_i\)。問至少成功 \(l\) 次且最後 \(K\leq0\) 的概率是多少。
資料範圍:\(0\leq K\leq2000,0\leq L\leq N\leq 200,-1\leq a_i\leq1000,0\leq p_i\leq100\)。
正文:
這道題 \(K\leq2000\) 很搞人,但是我們發現其實 \(K\) 至多到 \(200\)。畢竟 \(a_i\) 最少是 \(-1\)
搞定 \(K\) 以後,我們設 \(f_{i,j,k}\) 表示前 \(i\) 個任務成功了 \(j\) 個當前的 \(K\) 為 \(k\) 的概率。
得到轉移方程:
\[f_{i,j,k}=f_{i-1,j,k}\cdot(1-p_i)+f_{i-1,j,k-a_i}\cdot p_i \]很明顯,\(f_{0,0,K}=1\)。
程式碼:
double f[N][N][N * 2]; int a[N]; double p[N], ans; int n, l, K; 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]), a[i] = a[i] > 200? 200: a[i]; f[0][0][K + 200] = 1; for (int i = 1; i <= n; i++) for (int j = 0; j <= i; j++) for (int k = -200; k <= 200; k++) f[i][j][k + 200] = j > 0? f[i - 1][j][k + 200] * (1.0 - p[i]) + f[i - 1][j - 1][k - a[i] + 200] * p[i]: f[i - 1][j][k + 200] * (1.0 - p[i]); for (int i = l; i <= n; i++) for (int k = 200; k <= 400; k++) ans += f[n][i][k]; printf ("%.6lf", ans); return 0; }