目录
显示
题目链接
https://www.luogu.com.cn/problem/P3239
题解
根据期望的线性性,我们可以把每张牌使用的概率算出来,再把每张牌的期望伤害值相加即可得到答案。
现在问题变成了这个概率怎么求。
设第 \(i\) 张牌使用的概率为 \(g_i\)。
对于第一张牌,容易得知:
$$g_1=1-(1-p_1)^r$$
对于第二张牌,我们发现这个概率和第一张牌是否被取有关:
- 如果第一张牌被取了:由于第一张牌被取后当前轮立刻结束,因此我们只有 \(r-1\) 轮来决定是否取第二张牌。
- 如果第一张牌没被取:我们有 \(r\) 轮来决定是否取第二张牌。
设 \(f_{i,j}\) 表示 \(r\) 轮中考虑前 \(i\) 张牌,取 \(j\) 张的概率。边界显然是 \(f_{0,0}=1\)。
现在我们考虑第 \(i\) 张牌:
- 如果不取第 \(i\) 张牌:\(f_{i,j}=f_{i-1,j} \times (1-p_i)^{r-j}\)(取了 \(j\) 张意味着有 \(j\) 轮都没有考虑第 \(i\) 张牌);
- 如果取第 \(i\) 张牌:\(f_{i,j}=f_{i-1,j-1} \times (1-(1-p_i)^{r-j+1})\)。
有了这些信息,结合前面的推导,\(g_i\) 就很好推了:
$$g_i=\sum_{j=0}^r f_{i-1,j} \times (1-(1-p_i)^{r-j})$$
#include <cstdio>
#include <cstring>
#include <cmath>
double f[255][255],g[255],p[255];
int d[255];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
memset(f,0,sizeof(f));
memset(g,0,sizeof(g));
int n,r;
scanf("%d%d",&n,&r);
f[0][0]=1;
for(int i=1;i<=n;i++)
scanf("%lf%d",&p[i],&d[i]);
for(int i=1;i<=n;i++)
for(int j=0;j<=r;j++)
{
double tmp=pow(1-p[i],r-j);
f[i][j]=f[i-1][j]*tmp+(j>0)*f[i-1][j-1]*(1-tmp*(1-p[i]));
}
g[1]=(1-pow(1-p[1],r));
for(int i=2;i<=n;i++)
for(int j=0;j<=r;j++)
g[i]+=f[i-1][j]*(1-pow(1-p[i],r-j));
double ans=0;
for(int i=1;i<=n;i++)
ans+=g[i]*d[i];
printf("%.10lf\n",ans);
}
return 0;
}