题目:https://www.luogu.com.cn/problem/P3239
思路:
设g[i]为第i个牌出现的概率,
s[i][j]第i个,j局不发动的概率,
f[i][j]为r轮,前i个牌,有j个发动技能概率,
p[i],d[i]和题目中意义一样。
答案为g[i]*d[i](1<=i<=n),出现的概率*相应的概率,即为期望伤害。
g[i]的求法:
g[1]=1-(1-p[1])^r;
g[2]的情况要考虑第一张牌的情况,
1.如果第一张牌出现,那第一张牌出现的那一轮就不会有第二张牌出现:
概率为:(1-s[2][r-1]);
如果第一张牌不出现:
概率为:(1-s[2][r]);
结合这个例子,可以得到,对于任意的i>1,在第11张牌到i−1张牌在所有r轮内是否发动技能已经确定的情况下,第i张牌被发动技能的概率只取决于第11张牌到第i−1张牌中有多少张发动了技能。即如果有j张发动了技能,那么在此情况下第i张牌发动技能的概率为1−(1−p[i])^r−j。
对于f[i][j]:
如果第i张牌发动:f[i][j]+=f[i-1][j-1]*(1-s[i][r-j+1]);
如果第i张牌不发动:f[i][j]+=f[i-1][j]*s[i][r-j];
有两个特殊情况:
j=0,f[i][j]=f[i-1][j]*s[i][r-j];//没有一个会出现,包括第i个
j=i,f[i][j]=f[i-1][j-1]*(1-s[i][r-j+1]);//全都出现;
g[i]+=f[i-1][j]*(1-s[i][r-j]);(j<=i&&j<=r);//考虑前i-1个出现情况,求第i个出现情况。
代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 1e3 + 10;
int n,r;
double p[N],g[N],s[N][N];//s[i][j]第i个,j局不发动的概率
double f[N][N];//f[i][j],r轮,前i个牌,有j个发动技能概率
int d[N];
int main() {
int T;
cin>>T;
while(T--){
cin>>n>>r;
for(int i=1;i<=n;i++) cin>>p[i]>>d[i];
for(int i=1;i<=n;i++) g[i]=0;
memset(f,0,sizeof f);
for(int i=1;i<=n;i++){
s[i][0]=1;
for(int j=1;j<=r;j++)
s[i][j]=s[i][j-1]*(1-p[i]);
}
f[1][0]=s[1][r];
f[1][1]=1-f[1][0];
for(int i=2;i<=n;i++)
for(int j=0;j<=i&&j<=r;j++)
{ if(!j) f[i][j]=f[i-1][j]*s[i][r];
else{
if(i!=j){
f[i][j]+=f[i-1][j-1]*(1-s[i][r-j+1]);
f[i][j]+=f[i-1][j]*s[i][r-j];
}
else
f[i][j]=f[i-1][j-1]*(1-s[i][r-j+1]);
}
}
g[1]=f[1][1];
for(int i=2;i<=n;i++)
for(int j=0;j<=r&&j<=i-1;j++)
g[i]+=f[i-1][j]*(1-s[i][r-j]);
double ans=0;
for(int i=1;i<=n;i++)
ans+=g[i]*d[i];
printf("%.10lf\n",ans);
}
return 0;
}