「HNOI 2015」亚瑟王

\(Description\)

\(n\)张卡牌,每一张卡牌有\(p_i\)的概率发动,并造成\(d_i\)点伤害.一共有\(r\)轮,每一轮按照编号从小到大依次考虑,如果这张牌已经发动过则跳过该牌,否则以\(p_i\)的概率发动,如果发动成功则造成伤害然后结束该轮,否则跳过这张牌.问期望造成的伤害,\(T\)组询问

\(n<=220,r<=132,T<=444\)

\(Solution\)

这道的答案怎么算应该挺好想的吧.

\[\sum_{i=1}^n dp[i]*d[i]\]

\(dp[i]\) 表示第i张牌出现的概率.

但是现在问题就是怎么算\(dp\)数组啊?

\(dp[1]\)显然啊.为:

\[1-(1-p[1])^r\]

\((1-p[1])^r\)为一直不出的概率.

但是现在好像貌似只能看出来\(dp[1]\)\(QAQ\)

接续上\(dp\)了,我们令\(f[i][j]\)为在\(r\)轮中,前\(i\)张卡中一共出了\(j\)张的概率,

至于转移方程,还需要分类讨论一下:

\(Case\ 1:\)

\(f[i][j]\)\(f[i-1][j-1]\)转移

这表示选了第\(i\)张牌,现在在\(r\)轮中有\(j-1\)轮选的是\(i\)之前的牌,而\(i\)没有被选到,所以\(i\)被选到的轮数为\(:r-j+1\)

转移方程为:

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

$ Case 2:$
\(f[i][j]\)\(f[i-1][j]\)转移而来.

表示不选第i张牌

那么在\(r\)轮中已经过了\(r-j\)轮了,剩下的不选\(i\)的概率为\((1-p[i])^{r-j}\)

所以转移方程为:

\[f[i][j]=f[i-1][j]*(1-p[i])^{r-j}\]

现在算出来了\(f\)数组,接下来就要来算\(dp\)数组了

\[dp[i]=f[i-1][j]*(1-(1-p[i])^{r-j}\]

\(Code\)

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
#define rg register
#define file(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout);
using namespace std;
int read(){
    int x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9') f=(c=='-')?-1:1,c=getchar();
    while(c>='0'&&c<='9') x=x*10+c-48,c=getchar();
    return f*x;
}
int d[1001],r,n;
double f[1001][1001],power[1001][1001],p[1001],dp[1001];
void init(){
    memset(f,0,sizeof(f));
    memset(dp,0,sizeof(dp));
    n=read(),r=read();
    for(int i=1;i<=n;i++)
        scanf("%lf",&p[i]),d[i]=read();
    for(int i=1;i<=n;i++){
        power[i][0]=1;
        for(int j=1;j<=r;j++)
            power[i][j]=power[i][j-1]*(1-p[i]);
    }
}
void solve(){
    init();
    f[1][0]=power[1][r],f[1][1]=dp[1]=1.0-f[1][0];
    for(int i=2;i<=n;i++)
        for(int j=0;j<=min(i,r);j++){
            if(j)
                f[i][j]+=f[i-1][j-1]*(1.0-power[i][r-j+1]);
            if(i!=j) f[i][j]+=f[i-1][j]*power[i][r-j];
        }
    for(int i=2;i<=n;i++)
        for(int j=0;j<=min(i-1,r);j++)
            dp[i]+=f[i-1][j]*(1-power[i][r-j]);
    double ans=0;
    for(int i=1;i<=n;i++)
        ans+=dp[i]*d[i];
    printf("%0.10lf\n",ans);
}
int main(){
    int T=read();
    while(T--)
        solve();
}

猜你喜欢

转载自www.cnblogs.com/hbxblog/p/10413908.html