[HNOI2015]亚瑟王

题面

首先可以知道的是,牌与牌之间的期望收益互相不影响,所以我们对每种牌分开进行计算。所以我们设出状态,\(f_{i,j}\) 到第 \(i\) 种牌,已经过了 \(j\) 轮,第 \(i\) 种牌抽到的概率。

if(j) f[i][j]=(f[i-1][j-1]*(1.0-pow(1-a[i],r-j+1))+f[i][j]);
f[i][j]=(f[i-1][j]*pow(1-a[i],r-j)+f[i][j]);

第一行的意思是在后来的 \(r-j+1\) 轮中必有一次选到的概率是 \((1-(1-a_{i})^{r-j+1})\)

第二行就是在后来的这些轮里一次都选不上,这时的概率是 \((1-a_i)^{r-j}\)

最后的结果就是 \(\sum (1-(1-a_i)^{r-j})\times f_{i-1,j}\times d_i\)

\(f_{i-1,j}\) 时没被开到,后来有 \(1-(1-a_i)^{r-j}\) 的概率也开不到,那么当下被开到的概率就是乘积,再乘上收益就行。

#include <bits/stdc++.h>
using namespace std;
typedef double db;
const int maxn=320;
int T;
int n,r;
db a[maxn],f[maxn][maxn],ans;int d[maxn];
void clear()
{
	memset(f,0,sizeof(f)); ans=0;
}
int main()
{
	//freopen("p.in","r",stdin);
	scanf("%d",&T);
	while(T--)
	{
		clear();
		scanf("%d%d",&n,&r);
		for(int i=1;i<=n;i++)
		{
			scanf("%lf%d",&a[i],&d[i]);
		}
		f[0][0]=1;
		for(int i=1;i<=n;i++)
		{
			for(int j=0;j<=min(i,r);j++)
			{
				if(j) f[i][j]=(f[i-1][j-1]*(1.0-pow(1-a[i],r-j+1))+f[i][j]);
				f[i][j]=(f[i-1][j]*pow(1-a[i],r-j)+f[i][j]);
			}
		}
		for(int i=1;i<=n;i++)
		{
			for(int j=0;j<min(i,r);j++)
				 ans+=d[i]*f[i-1][j]*(1.0-pow(1-a[i],r-j));
		}
		printf("%.10f\n",ans);
	}
}
posted @ 2022-10-19 22:51  cc0000  阅读(32)  评论(0)    收藏  举报