bzoj 4008 [HNOI2015] 亚瑟王

bzoj 4008 [HNOI2015] 亚瑟王

题面

[题面][https://www.lydsy.com/JudgeOnline/problem.php?id=4008]

题解

我们令(f[i][j])表示当前考虑了前(i)张卡牌,前(i)张牌一共剩下(j)次机会的概率是多少

那么(f[0][r]=1)

然后递推地求解

如果第(i+1)张卡牌没有用到 那么(f[i+1][j]+=f[i][j] imes (1-p[i+1])^j)

如果第(i+1)张卡牌被用到了,那么少了一次机会,多了一些伤害

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

然后答案会加(f[i][j] imes(1-(1-p[i+1])^j) imes d[i+1])

就是概率乘伤害

Review

这题据TRCYX说是NewTrain最难得期望dp

我觉得主要是状态难想,因为考虑到某一张牌只和前面的牌有关,和后面的牌无关,而且出牌的顺序也不影响答案,于是把(r)轮搞成(r)次机会,所以想到这个状态

Code

#include<stdio.h>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<iostream>
#include<queue>
#include<string>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<long long,long long> pll;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define rep(i,j,k)  for(register int i=(int)(j);i<=(int)(k);i++)
#define rrep(i,j,k) for(register int i=(int)(j);i>=(int)(k);i--)

ll read(){
	ll x=0,f=1;char c=getchar();
	while(c<'0' || c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0' && c<='9'){x=x*10+c-'0';c=getchar();}
	return x*f;
}

int T;
int n,r,d[255];
double p[255];
double f[255][255],pw[255][255];

int main()
{
	T=read();
	while(T--)
	{
		n=read();r=read();
		memset(f,0,sizeof(f));
		for(int i=1;i<=n;i++)
		{
			scanf("%lf",&p[i]);
			d[i]=read();
		}
		double ans=0;
		for(int i=1;i<=n;i++)
		{
			pw[i][0]=1;
			for(int j=1;j<=r;j++)pw[i][j]=pw[i][j-1]*(1-p[i]);
		}
		f[0][r]=1;
		for(int i=0;i<n;i++)
			for(int j=0;j<=r;j++)
			{
				f[i+1][j]+=f[i][j]*pw[i+1][j];
				if(j-1>=0)
				{
					f[i+1][j-1]+=f[i][j]*(1-pw[i+1][j]);
					ans+=f[i][j]*(1-pw[i+1][j])*d[i+1];
				}
			}
		printf("%.10lf
",ans);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/wawawa8/p/9557552.html