1. 程式人生 > 實用技巧 >【YBTOJ】守衛挑戰

【YBTOJ】守衛挑戰

題目大意:

\(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\)

,就是最多加上 \(n\)\(-1\) 才會對結果有影響。那麼我們確定了 \(K\) 最終的範圍:\(-200\leq K\leq200\)

搞定 \(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;
}