BZOJ 4008: [HNOI2015]亚瑟王 [DP 概率]

Posted Candy?

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 4008: [HNOI2015]亚瑟王 [DP 概率]相关的知识,希望对你有一定的参考价值。

传送门

题意:

$r$轮$n$张卡牌,每一轮依次考虑每张卡牌,$p_i$概率发动造成$d_i$伤害后结束本轮或者继续考虑下一张

每张卡牌发动过之后以后都会跳过

求$r$轮之后的期望伤害


 

看了一节课出题人的做法,并不知道该怎么写代码,感觉带着除法精度好玄学....

发现网上的题解都是另一种做法

$f[i][j]$表示第$i$张牌被考虑了$j$次的概率

有两个转移:

$1.\ $上一张牌考虑了$j$次都不发动

$2.\ $上一张牌考虑了$j+1$次,之前$k$次不发动,第$k$次发动了,$a*\sum\limits_{k=0}^{j}{(1-a)^k}$等比数列求和

$f[i][j]=f[i-1][j]*(1-p_{i-1})^j\ +\ f[i-1][j+1]*(1-(1-p_{i-1})^{j+1})$

 

我现在还不太明白两种做法有什么联系

 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;
const int N=225;
typedef double ld;
inline int read(){
    char c=getchar();int x=0,f=1;
    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 n,r,d[N];
double x;
ld p[N],f[N][N];
ld g[N][N];
int main(){
    freopen("in","r",stdin);
    int T=read();
    while(T--){
        //memset(f,0,sizeof(f));
        n=read();r=read();
        for(int i=1;i<=n;i++) 
            scanf("%lf",&x),p[i]=x,d[i]=read();
        memset(f[0],0,sizeof(f[0]));
        f[0][r]=1;
        ld ans=0;
        for(int i=1;i<=r;i++) g[0][i]=1;
        for(int i=1;i<=n;i++) g[i][0]=1;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=r;j++){
                f[i][j]=f[i-1][j]*g[i-1][j];
                if(j+1<=r) f[i][j]+=f[i-1][j+1]*( 1-g[i-1][j+1] );
                g[i][j]=g[i][j-1]*(1-p[i]);
                ans+=f[i][j]*( 1-g[i][j] )*d[i];
            }
        printf("%.10lf\n",(double)ans);
    }
}

 

以上是关于BZOJ 4008: [HNOI2015]亚瑟王 [DP 概率]的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ-4008: [HNOI2015]亚瑟王 (概率期望DP)

BZOJ4008 [HNOI2015]亚瑟王

BZOJ 4008 HNOI2015 亚瑟王

bzoj4008 HNOI2015—亚瑟王

BZOJ 4008: [HNOI2015]亚瑟王( dp )

[BZOJ 4008][HNOI2015]亚瑟王(期望Dp)