zoukankan      html  css  js  c++  java
  • 【期望DP】BZOJ4008- [HNOI2015]亚瑟王

    题目大意

    (n)张卡牌,(r)轮游戏。每张卡牌只能用至多一次,每张卡牌被用到的概率为(p_i)。现在从左往右轮,直到最右一张卡片或者某张卡片被用到。如果某张卡牌被用到,产生(d_i)的贡献,回合结束。求期望得分。

    思路

    神思路。我们用(f[i,j])表示第i张牌得到j个机会的概率(包括被用过后跳掉的)。注意是恰巧得到j个机会,而不是得到至多j个机会或在第j轮被使用到。
    对于(f[i-1.j])的转移,我们考虑以下两种情况:
    ①第i-1张牌也得到了j个机会,并且以此都没有被用到过。则有

    [f[i,j]=f[i-1,j]*(1-p_(i-1))^j ]

    ②第i张牌得到了j-1个机会,并且被用到了一次。我们考虑这种情况发生的概率为:

    [p_(i-1)+p_(i-1)*(1-p_(i-1))+…+p_(i-1)*(1-p_(i-1))^j ]

    上式为等比数列,化简后则有:

    [f[i,j]=f[i-1,j+1]*(1-(1-p_(i-1)^j) ]

    所以

    [f[i,j]=f[i-1,j]*(1-p_(i-1))^j+f[i-1,j+1]*(1-(1-p_(i-1)^j) ]

    最后的答案为:

    [ans=∑f[i,j]*(1-(1-p_i)^j)*d_i ]

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    const int MAXN=220+5;
    const int MAXR=132+5;
    double p[MAXN];
    int d[MAXN];
    double f[MAXN][MAXR];
    int n,r;
    
    void init()
    {
    	scanf("%d%d",&n,&r);
    	for (int i=1;i<=n;i++) scanf("%lf%d",&p[i],&d[i]);
    }
    
    void dp()
    {
    	double ans=0;
    	memset(f,0,sizeof(f));
    	f[0][r]=1;
    	for (int i=1;i<=n;i++)
    		for (int j=1;j<=r;j++)
    		{
    			f[i][j]=f[i-1][j]*pow(1-p[i-1],j)+f[i-1][j+1]*(1-pow(1-p[i-1],j+1));
    			ans+=f[i][j]*(1-pow(1-p[i],j))*d[i];
    		}
    	printf("%.10lf
    ",ans);
    }
    
    int main()
    {
    	int T;
    	scanf("%d",&T);
    	while (T--)
    	{
    		init();
    		dp();
    	}
    	return 0;
    }
    
  • 相关阅读:
    java8 Stream排序字段为空排序方法
    SpringBoot使用token简单鉴权的具体实现方法
    性能调优
    TestNG最简单的测试
    TestNG异常测试
    TestNG中如何执行测试
    TestNG的基本注解
    TestNG介绍
    TestNG 环境搭建
    python第四课笔记
  • 原文地址:https://www.cnblogs.com/iiyiyi/p/5779552.html
Copyright © 2011-2022 走看看