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:

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

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

  • 相关阅读:
    乘法DAC一点知识
    #4 判断字符串是否为整数
    #3 不使用循环输出1到100
    #2 判断一个字符串是否包含重复字符
    #22 结语
    #1 组成互不相同且不重复的三位数
    #21 Python异常
    #19 re&jieba模块
    2020国庆正睿笔记
    2019正睿csp-s赛前冲刺
  • 原文地址:https://www.cnblogs.com/newera/p/9139412.html
Copyright © 2011-2022 走看看