首先可以知道的是,牌与牌之间的期望收益互相不影响,所以我们对每种牌分开进行计算。所以我们设出状态,\(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);
}
}
标签:概率,int,pow,clear,maxn,HNOI2015,亚瑟王
From: https://www.cnblogs.com/cc0000/p/16808153.html