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;
    }
    
  • 相关阅读:
    UVALive 6584 Escape (Regionals 2013 >> Europe
    莫比乌斯反演
    POJ 3986 Math teacher's homework
    ACM一些题目
    重探 DFT
    GDSOI2015 task4 ACU
    GDSOI2015 task2 覆盖半径
    USACO 2005 January Gold The Wedding Juicer
    CQOI2015 选数
    计算圆的包含(两两圆不相交)
  • 原文地址:https://www.cnblogs.com/encodetalker/p/10808033.html
Copyright © 2011-2022 走看看