【ybt金牌导航1-1-9】守卫挑战

守卫挑战

题目链接: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=fi1,j,k+ai×(1.0pi)fi,j,k+ai=fi1,j,k+ai×(1.0pi)+fi1,j1,k×pi(j=0)(j>0)
当然,要记得 k k k 值要与 200 200 200 取最小值。
而且你会发现 k k k 的范围是 − 200 ∼ 200 -200\sim200 200200,那就要把所有的 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 Ln,然后在枚举最后 K K K 的值 j j j,范围是 0 ∼ 200 ( + 200 ) 0\sim200(+200) 0200(+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;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值