HNOI2015 亚瑟王(概率DP)

传送门

考虑对每张牌求出出掉它的概率那么期望就可以轻易算出
一张牌被考虑的次数与考虑到它的轮数有关,而考虑到一个点的轮数与前面选了几张牌有关
于是令 f [ i ] [ j ] f[i][j] 表示 r r 轮中,第 i i 个之前及 i i 选了 j j 个的概率
那么一张牌最后出出去的概率就是
p i = j = 0 i 1 f [ i 1 ] [ j ] ( 1 ( 1 p ) r j ) p_i=\sum_{j=0}^{i-1}f[i-1][j]*(1-(1-p)^{r-j})
f f 的转移枚举当前选不选就可以了
f [ i ] [ j ] = f [ i 1 ] [ j ] ( 1 p ) r j + f [ i 1 ] [ j 1 ] ( 1 ( 1 p ) r ( j 1 ) ) f[i][j]=f[i-1][j]*(1-p)^{r-j}+f[i-1][j-1]*(1-(1-p)^{r-(j-1)})

#include<bits/stdc++.h>
#define cs const
using namespace std;
cs int N = 225;
int T, n, r;
double p[N]; int d[N];
double pw[N][N], f[N][N];
int main(){
	scanf("%d", &T);
	while(T--){
		scanf("%d%d", &n, &r);
		for(int i = 1; i <= n; i++){
			scanf("%lf%d", &p[i], &d[i]);
			pw[i][0] = 1; 
			for(int j = 1; j <= r; j++) pw[i][j] = pw[i][j - 1] * (1 - p[i]);
		}
		f[0][0] = 1;
		for(int i = 1; i <= n; i++){
			for(int j = 0; j <= r; j++){
				f[i][j] = f[i - 1][j] * pw[i][r - j] + f[i - 1][j - 1] * (1 - pw[i][r - j + 1]);
			}
		} double ans = 0;
		for(int i = 1; i <= n; i++){
			double p = 0;
			for(int j = 0; j < r; j++) p += f[i - 1][j] * (1 - pw[i][r - j]);
			ans += p * d[i];			
		} printf("%.10lf\n", ans);
	} return 0;
}
发布了610 篇原创文章 · 获赞 94 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/sslz_fsy/article/details/103602215