zoukankan      html  css  js  c++  java
  • [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
    ",res);
        }
        return 0;
    }

    Review:

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

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

  • 相关阅读:
    “百度杯”CTF比赛 九月场 code
    初识thinkphp(3)
    i春秋CTF web题(1)
    初识thinkphp(2)
    初识thinkphp(1)
    0MQ底层队列设计
    0MQ文档导读
    LF模式是个坑,ZeroIce中间件让你体会这个痛
    0xe7f001f0!?NDK调试过程,无故抛出SIGSEGV。
    KDevelop
  • 原文地址:https://www.cnblogs.com/newera/p/9139412.html
Copyright © 2011-2022 走看看