[BZOJ 4008] 亚瑟王

Link:

BZOJ 4008 传送门

Solution:

这题的约束:

(1)若一张牌发动了技能,那么将结束此回合。

(2)若一张牌发动过技能那么它不能再发动技能。

这意味着不能以回合数为状态来进行$dp$

由(2):一张牌最多发动一次技能,于是只要能算出每张牌的发动概率再统计即可

因此需要考虑经过卡牌的次数就好了,即给卡牌机会

 

设$dp[i][j]$表示给第$i$个元素分配$j$个机会的概率:

(1)若i-1没有用一个机会那么$dp[i][j]+=dp[i-1][j]*(1-dat[i-1])^j$

(2)若i-1用了一个机会那么$dp[i][j]+=dp[i-1][j+1]*(1-(1-dat[i-1])^j)$

(Note:这里并不用对每个卡牌只能发动一次进行特殊处理,简化为发动次数$>=1$的情况即可,毕竟结果只计算了一次

Code:

//by NewErA
#include <bits/stdc++.h>

using namespace std;
const int MAXN=500;
int n,r,T;
double d[MAXN],pw[MAXN][MAXN],dat[MAXN],dp[MAXN][MAXN];

int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&r);memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++) scanf("%lf%lf",&dat[i],&d[i]);
        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-dat[i]);
        }
        
        double res=0;dp[0][r]=1;
        for(int i=0;i<n;i++)
            for(int j=0;j<=r;j++)
            {
                dp[i+1][j]+=dp[i][j]*pw[i+1][j];
                if(j>=1)
                {
                    dp[i+1][j-1]+=dp[i][j]*(1-pw[i+1][j]);
                    res+=dp[i][j]*(1-pw[i+1][j])*d[i+1];
                }
            }
        printf("%.10lf\n",res);
    }
    return 0;
}

Review:

题目特点出发寻找状态的设定

如果各项独立,分开来计算

 

posted @ 2018-06-05 13:51  NewErA  阅读(145)  评论(0编辑  收藏  举报