洛谷 P3239 [HNOI2015]亚瑟王(期望dp)

题面

luogu

题解

一道复杂的期望\(dp\)

思路来源:__stdcall

容易想到,只要把每张牌打出的概率算出来就可以求出\(ans\)

\(fp[i]\)表示把第\(i\)张牌打出来的概率

可知:\(fp[0] = 1-(1-p[0])^r\)
\((1-p[0])^r\)即一直不打出的概率)

后面的\(fp\)怎么求?

\(f[i][j]\)表示前\(i\)张牌一共出了\(j\)张的概率, 那么就会有

\(fp[i] = \sum_{j=0}^{r}f[i-1][j]*(1-(1-p[i])^{r-j})\)
\(1−(1−p[i])^{r−j}\)就是在\(r−j\)轮中使用过第\(i\)张牌的概率)

那么问题只有如何求\(f\)

对于第\(i\)张牌,只有两种情况:
1.使用
\(f[i][j] += f[i-1][j-1]*(1-(1-p[i])^{r-j+1})\)

2.不使用
\(f[i][j] += f[i-1][j]*(1-p[i])^{r-j}\)

具体看代码。。
看完题解还是很容易的。。

Code

#include<bits/stdc++.h>

#define LL long long
#define RG register

using namespace std;
template<class T> inline void read(T &x) {
	x = 0; RG char c = getchar(); bool f = 0;
	while (c != '-' && (c < '0' || c > '9')) c = getchar(); if (c == '-') c = getchar(), f = 1;
	while (c >= '0' && c <= '9') x = x*10+c-48, c = getchar();
	x = f ? -x : x;
	return ;
}
template<class T> inline void write(T x) {
	if (!x) {putchar(48);return ;}
	if (x < 0) x = -x, putchar('-');
	int len = -1, z[20]; while (x > 0) z[++len] = x%10, x /= 10;
	for (RG int i = len; i >= 0; i--) putchar(z[i]+48);return ;
}

const int N = 230;

double p[N], fp[N], P[N][N], f[N][N];
int d[N], n, r;
void pre() {
	for (int i = 1; i <= n; i++) {
		P[i][0] = 1;
		for (int j = 1; j <= r; j++)
			P[i][j] = P[i][j-1]*(1-p[i]);
	}
	return ;
}

void solve() {
	read(n); read(r);
	for (int i = 1; i <= n; i++)
		scanf("%lf", &p[i]), read(d[i]);
	pre();
	memset(f, 0, sizeof(f));
	memset(fp, 0, sizeof(fp));
	f[1][0] = P[1][r];
	f[1][1] = fp[1] = 1-f[1][0];
	for (int i = 2; i <= n; i++) {
		for (int j = 0; j <= r; j++) {
			f[i][j] += f[i-1][j]*P[i][r-j];
			if (j) f[i][j] += f[i-1][j-1]*(1-P[i][r-j+1]);
		}
	}
	for (int i = 2; i <= n; i++)
		for (int j = 0; j <= r; j++)
			fp[i] += f[i-1][j]*(1-P[i][r-j]);
	double ans = 0;
	for (int i = 1; i <= n; i++)
		ans += fp[i]*d[i];
	printf("%lf\n", ans);
	return ;
}

int main() {
	int T; read(T);
	while (T--) solve();
	return 0;
}

posted @ 2019-01-10 11:11  zzy2005  阅读(158)  评论(0编辑  收藏  举报