「HNOI2015」亚瑟王

传送门

Description

小 K 不慎被 LL 邪教洗脑了,洗脑程度深到他甚至想要从亚瑟王邪教中脱坑。

他决定,在脱坑之前,最后再来打一盘亚瑟王。既然是最后一战,就一定要打得漂亮。众所周知,亚瑟王是一个看脸的游戏,技能的发动都是看概率的。作为一个非洲人,同时作为一个前 OIer,小 K 自然是希望最大化造成伤害的期望值。但他已经多年没写过代码,连 Spaly 都敲不对了,因此,希望你能帮帮小 K,让他感受一下当欧洲人是怎样的体验。

本题中我们将考虑游戏的一个简化版模型。

玩家有一套卡牌,共 (n) 张。游戏时,玩家将 (n) 张卡牌排列成某种顺序,排列后将卡牌按从前往后依次编号为 (1 sim n)。本题中,顺序已经确定,即为输入的顺序。

每张卡牌都有一个技能。第 (i) 张卡牌的技能发动概率为 (p_i),如果成功发动,则会对敌方造成 (d_i) 点伤害。也只有通过发动技能,卡牌才能对敌方造成伤害。基于现实因素以及小 K 非洲血统的考虑,(p_i) 不会为 0,也不会为 1,即 (0 < p_i < 1)

一局游戏一共有 (r) 轮。在每一轮中,系统将从第一张卡牌开始,按照顺序依次考虑每张卡牌。在一轮中,对于依次考虑的每一张卡牌:

  1. 如果这张卡牌在这一局游戏中已经发动过技能,则
    1.1 如果这张卡牌不是最后一张,则跳过之(考虑下一张卡牌); 否则(是最后一张),结束这一轮游戏。
  2. 否则(这张卡牌在这一局游戏中没有发动过技能),设这张卡牌为第 (i) 张。
    2.1 将其以 (p_i) 的概率发动技能。
    2.2 如果技能发动,则对敌方造成 (d_i)点伤害,并结束这一轮。
    2.3 如果这张卡牌已经是最后一张(即 (i) 等于 (n)),则结束这一轮;否则,考虑下一张卡牌。

请帮助小 K 求出这一套卡牌在一局游戏中能造成的伤害的期望值。

Solution

本题想到对于每个卡牌单独求概率并不难

难点在于每轮在取到卡牌后就会停止,所以如果是对游戏过程进行(dp)会非常麻烦

因为你可能需要考虑当前以获得卡牌的集合

题解的做法巧妙地排除了这方面的难题,转而对序列本身进行(dp)

因为轮数是已知的,并且数列的顺序也是已知的

未知的是每一轮的停止位置,所以本题的(dp)实质上是在对每一轮的结束位置进行(dp)

(dp[i][j])表示全局结束后,前(i)个中选了(j)个的概率,(f[i])表示第(i)个被选上的概率,(p[i])表示输入的那个概率。考虑是否选择第(i)个数进行转移,并把选择第(i)个数的贡献计入(f[i])


Code 

#include<bits/stdc++.h>
#define ll long long
#define dbg1(x) cerr<<#x<<"="<<(x)<<" "
#define dbg2(x) cerr<<#x<<"="<<(x)<<"
"
#define dbg3(x) cerr<<#x<<"
"
using namespace std;
#define reg register
#define db double
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
	return x*f;
}
const int MN=225,MR=137;
int n,r,d[MN];
db p[MN],pw[MN][MN],f[MN][MN],P[MN],ans;
int main()
{
	int Cas=read();
	reg int i,j;
	while(Cas--)
	{
		n=read();r=read();
		for(i=1;i<=n;++i)scanf("%lf",&p[i]),d[i]=read();
		memset(f,0,sizeof f);
		memset(P,0,sizeof P);
		reg int i,j;
        for(i=1;i<=n;++i)for(pw[i][0]=j=1;j<=r;++j)
            pw[i][j]=pw[i][j-1]*(1.-p[i]);
        f[1][0]=pw[1][r];f[1][1]=P[1]=1.-f[1][0];
        for(i=2;i<=n;++i)for(j=0;j<=r&&j<=i;++j)
		{
            f[i][j]+=f[i-1][j]*pw[i][r-j];
            if(j) f[i][j]+=f[i-1][j-1]*(1-pw[i][r-j+1]),
                P[i]+=f[i-1][j-1]*(1-pw[i][r-j+1]);
        }
        ans=0.;
        for(i=1;i<=n;++i)ans+=P[i]*(db)d[i];
        printf("%.10lf
",ans);
	}
	return 0;
}


Blog来自PaperCloud,未经允许,请勿转载,TKS!

原文地址:https://www.cnblogs.com/PaperCloud/p/11625516.html