「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)<<"\n"
#define dbg3(x) cerr<<#x<<"\n"
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\n",ans);
    }
    return 0;
}



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

猜你喜欢

转载自www.cnblogs.com/PaperCloud/p/11625516.html