bzoj 4008 亚瑟王 期望概率dp

对于这种看起来就比较傻逼麻烦的题,最关键的就是想怎么巧妙的设置状态数组,使转移尽可能的简洁。
一开始我想的是f[i][j]表示到第j轮第i张牌还没有被选的概率,后来发现转移起来特别坑爹,还会有重的或漏的情况。
于是改变想法:
f[i][j]表示考虑到前i张牌,还剩j轮的概率

转移也就简单了,下一张牌有两种可能,选或不选:

f[i+1][j]=f[i][j]*(1-p[i+1])^j 

f[i+1][j-1]=f[i][j]*(1-(1-p[i+1])^j)

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int n,r;
double po[225][140],p[225],k[225],f[225][140],ans;
int main()
{
	register int i,j,T;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d",&n,&r);
		for(i=1;i<=n;i++)
			scanf("%lf%lf",&p[i],&k[i]);
		for(i=1;i<=n;i++){
			po[i][0]=1;
			for(j=1;j<=r;j++)
				po[i][j]=po[i][j-1]*(1-p[i]);
		}
		memset(f,0,sizeof(f));
		f[0][r]=1; ans=0;
		for(i=1;i<=n;i++)
		{
			for(j=0;j<=r;j++)
			{
				f[i][j]+=f[i-1][j]*po[i][j];
				f[i][j]+=f[i-1][j+1]*(1-po[i][j+1]);
				ans+=f[i-1][j+1]*(1-po[i][j+1])*k[i];
			}
		}
		printf("%0.10lf\n",ans);
	}
	return 0;
}


posted @ 2017-07-09 17:28  Ren_Ivan  阅读(82)  评论(0编辑  收藏  举报