zoukankan      html  css  js  c++  java
  • bzoj4008 [HNOI2015]亚瑟王

    题目链接:bzoj4008

    对于答案的计算有一个很显然的思路,记第(i)张卡牌在游戏中被发动的概率为(f_i),则(Ans=sum_{i=1}^nf_id_i)

    考虑如何计算(f_i),可以用(1-)不发动这张卡牌的概率

    不发动这张卡牌的概率(=(1-p_i)^{它被考虑的轮数}*1^{它不被考虑的轮数}*该局面出现的概率)

    对于最后一项可以考虑dp,记(dp_{i,j})表示前(i)张卡牌中发动(j)张的概率,按照当前是否发动第(i)张进行转移

    1)发动第(i)张,那么首先(j>0),其次在(j-1)轮中,由于发动了(i)之前的卡牌故不会考虑(i),所以这种情况对(dp_{i,j})的贡献为(dp_{i-1,j-1}*(1-(1-p_i)^{r-(j-1)}))

    2)不发动第(i)张,和第一种同理,对答案贡献为(dp_{i-1,j}(1-p_i)^{r-j}),注意此时(i eq j)

    综合起来就是

    [dp_{i,j}=dp_{i-1,j-1}*(1-(1-p_i))^{r-(j-1)}+dp_{i-1,j}*(1-p_i)^{r-j} ]

    好了现在(f_i)的计算就比较轻松了,枚举在(i)之前选了(j)张卡牌,那么在这(j)轮是不会考虑(i)这一张卡牌的,故

    [f_i=sum_{j=0}^{min(i-1,r)}dp_{i-1,j}(1-(1-p_i)^{r-j}) ]

    预处理((1-p_i)^j)以加速运算

    #include<iostream>
    #include<string.h>
    #include<string>
    #include<stdio.h>
    #include<algorithm>
    #include<vector>
    #include<queue>
    #include<map>
    using namespace std;
    int n,m,r,d[1010],t;
    double p[1010],powe[1010][1010],dp[1010][1010],f[1010];
    
    int read()
    {
        int x=0,f=1;char ch=getchar();
        while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
        while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
        return x*f;
    }
    
    void init()
    {
        n=read();r=read();
        memset(f,0.0,sizeof(f));
        memset(dp,0.0,sizeof(dp));
        int i,j;
        for (i=1;i<=n;i++) scanf("%lf%d",&p[i],&d[i]);
        for (i=1;i<=n;i++)
        {
            powe[i][0]=1.0;
            for (j=1;j<=r;j++) powe[i][j]=powe[i][j-1]*(1-p[i]);
        }
    }
    
    void work()
    {
        int i,j;
        dp[1][1]=1.0-powe[1][r];dp[1][0]=powe[1][r];
        for (i=2;i<=n;i++)
        {
            for (j=0;j<=min(i,r);j++)
            {
                if (j) dp[i][j]+=dp[i-1][j-1]*(1.0-powe[i][r-j+1]); 
                if (i!=j) dp[i][j]+=dp[i-1][j]*powe[i][r-j];
            }
        }
    }
    
    void out()
    {
        double ans=0.0;f[1]=1-powe[1][r];
        int i,j;
        for (i=2;i<=n;i++) 
        {
            for (j=0;j<=min(i-1,r);j++)
                f[i]+=dp[i-1][j]*(1.0-powe[i][r-j]);
        }
        for (i=1;i<=n;i++) ans+=f[i]*d[i];
        printf("%0.10lf
    ",ans);
    }
    
    int main()
    {
        t=read();
        while (t--)
        {
            init();
            work();
            out();
        }
        return 0;
    }
    
  • 相关阅读:
    A1023 Have Fun with Numbers (20分)(大整数四则运算)
    A1096 Consecutive Factors (20分)(质数分解)
    A1078 Hashing (25分)(哈希表、平方探测法)
    A1015 Reversible Primes (20分)(素数判断,进制转换)
    A1081 Rational Sum (20分)
    A1088 Rational Arithmetic (20分)
    A1049 Counting Ones (30分)
    A1008 Elevator (20分)
    A1059 Prime Factors (25分)
    A1155 Heap Paths (30分)
  • 原文地址:https://www.cnblogs.com/encodetalker/p/10808033.html
Copyright © 2011-2022 走看看