P3239题解
P3269亚瑟王
题意理解
给出 \(n\) 张牌依次使用 \(r\) 轮,其中已使用的不得再次使用,每张牌以 \(p_i\) 的概率使用,使用成功则打出 \(d_i\) 的伤害,求最终伤害的期望。
题目解析
既然要求期望,那么我们可以考虑先求出每张牌打出的概率 \(g_i\),答案即为
\[\sum_{i=1}^n g_id_i
\]
于是题目就转为如何求 \(g_i\)。
如果是第 \(1\) 张,则每轮有 \(1-p_1\) 的概率不被打出,\(r\) 轮打出的概率就是 \(1-(1-p_1)^r\)。
如果是第 \(i\) 张,此时我们肯定不能直接求了,考虑dp。定义一个数组 \(f\),\(f_{i,j}\) 表示前 \(i\) 张牌中,\(r\) 轮打出了 \(j\) 张。那么转移方程如下:
1.如果第 \(i\) 张牌打出,则
\[f_{i,j}=f_{i-1,j-1}(1-(1-p_i)^{r-(j-1)})
\]
2.如果第 \(i\) 张牌没被打出,则
\[f_{i,j}=f_{i-1,j}(1-p_i)^{r-j}
\]
因为前 \(i\) 张牌中不可能打出超过 \(i\) 张牌,所以 \((i\ne j)\)
然后用 \(f\) 求 \(g\) 可以用下式:
\[g_i=\sum_{j=0}^{min(i-1,r)} f_{i-1,j}*(1-(1-p_i)^{r-j})
\]
此时,第 \(i\) 张牌的使用概率前 \(i\) 张牌中,第 \(j\) 张使用他的概率之和。
代码
#include<bits/stdc++.h>
using namespace std;
//#define int long long
const int N=220+5;
int T;
int n,r;
double p[N],pw[N][N];
int d[N];
double f[N][N],g[N];
double ans;
int main()
{
cin>>T;
while(T--)
{
memset(f,0,sizeof(f));
memset(g,0,sizeof(g));
memset(pw,0,sizeof(pw));
cin>>n>>r;
for(int i=1;i<=n;i++)cin>>p[i]>>d[i];
for(int i=1;i<=n;i++)pw[i][0]=1;
if(!r)
{
printf("%.10lf\n",0);
continue;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=r;j++)
pw[i][j]=pw[i][j-1]*(1.0-p[i]);//预处理(1-p[i])^j
f[1][0]=pw[1][r];
f[1][1]=g[1]=1.0-pw[1][r];
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-pw[i][r-j+1]);
if(i!=j)f[i][j]+=f[i-1][j]*pw[i][r-j];
}
}
for(int i=2;i<=n;i++)
for(int j=0;j<=min(i-1,r);j++)
g[i]+=f[i-1][j]*(1.0-pw[i][r-j]);
ans=0;
for(int i=1;i<=n;i++)ans+=g[i]*d[i];
printf("%.10lf\n",ans);
}
}

浙公网安备 33010602011771号