题目链接
题目解法
根据期望的线性性,可以算出每张卡牌伤害的期望值,然后累加起来就是答案
如果令第
i
i
i 张卡牌在
r
r
r 轮中被发动的概率为
g
[
i
]
g[i]
g[i]
那么答案就是
∑
i
=
1
n
g
[
i
]
∗
d
[
i
]
\sum_{i=1}^{n}g[i]*d[i]
∑i=1ng[i]∗d[i]
现在考虑计算
g
[
i
]
g[i]
g[i]
显然有
g
[
1
]
=
1
−
(
1
−
p
[
i
]
)
r
g[1]=1-(1-p[i])^r
g[1]=1−(1−p[i])r
对于
i
=
2
…
n
i=2…n
i=2…n,考虑用
1
1
1 减去不合法的概率
可以枚举前
i
−
1
i-1
i−1 个数在
r
r
r 轮中一共被发动的张数
即
g
[
i
]
=
1
−
∑
j
=
0
m
i
n
(
r
,
i
−
1
)
f
[
i
−
1
]
[
j
]
∗
(
1
−
p
[
i
]
)
r
−
j
g[i]=1-\sum_{j=0}^{min(r,i-1)}f[i-1][j]*(1-p[i])^{r-j}
g[i]=1−∑j=0min(r,i−1)f[i−1][j]∗(1−p[i])r−j
其中
f
[
i
]
[
j
]
f[i][j]
f[i][j] 表示在
[
1
,
i
]
[1,i]
[1,i] 中,
r
r
r 轮后有
j
j
j 张卡牌被发动的概率
这个表达式是由还没走到
i
i
i 就结束的概率
∗
*
∗ 走到
i
i
i 但不发动的概率
下面考虑计算
f
[
i
]
[
j
]
f[i][j]
f[i][j]
分成
2
2
2 种情况
1.
1.
1.
i
i
i 在
r
r
r 轮中不发动,即
f
[
i
]
[
j
]
=
f
[
i
−
1
]
[
j
]
∗
(
1
−
p
[
i
]
)
r
−
j
f[i][j]=f[i-1][j]*(1-p[i])^{r-j}
f[i][j]=f[i−1][j]∗(1−p[i])r−j,即有
j
j
j 次没走到
i
i
i 就结束了,其他都是没发动
2.
2.
2.
i
i
i 在
r
r
r 轮中发动,继续考虑容斥,即用
1
−
1-
1− 不发动的概率,即
f
[
i
]
[
j
]
=
f
[
i
−
1
]
[
j
−
1
]
∗
(
1
−
(
1
−
p
[
i
]
)
r
−
j
+
1
)
f[i][j]=f[i-1][j-1]*(1-(1-p[i])^{r-j+1})
f[i][j]=f[i−1][j−1]∗(1−(1−p[i])r−j+1)
这样就可以在
O
(
T
n
r
)
O(Tnr)
O(Tnr) 的时间复杂度解决问题
多测要清空
#include <bits/stdc++.h>
using namespace std;
const int N(230);
double p[N],f[N][N],g[N];
int d[N];
//f[i][j]:在所有的r轮中,在1到i中一共选了j张的概率
//g[i]:用第i张卡牌的概率
inline int read(){
int FF=0,RR=1;
char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
return FF*RR;
}
double qmi(double a,int b){
double res=1;
for(;b;b>>=1){
if(b&1) res*=a;
a*=a;
}
return res;
}
void init(){
for(int i=0;i<N;i++) for(int j=0;j<N;j++) f[i][j]=0;
for(int i=0;i<N;i++) g[i]=0;
}
void work(){
init();
int n,r;scanf("%d%d",&n,&r);
for(int i=1;i<=n;i++)
scanf("%lf%d",&p[i],&d[i]);
f[0][0]=1;
for(int i=1;i<=n;i++)
for(int j=0;j<=min(i,r);j++){
//选i
if(j) f[i][j]+=f[i-1][j-1]*(1-qmi(1-p[i],r-j+1));
//不选i
f[i][j]+=f[i-1][j]*qmi(1-p[i],r-j);
}
g[1]=1.0-qmi(1-p[1],r);
for(int i=2;i<=n;i++){
g[i]=1.0;
for(int j=0;j<=min(r,i-1);j++)//有j轮用了[1,i-1]中的卡牌
g[i]-=f[i-1][j]*qmi(1-p[i],r-j);
}
double ans=0;
for(int i=1;i<=n;i++) ans+=g[i]*d[i];
printf("%.10lf\n",ans);
}
int main(){
int T;scanf("%d",&T);
while(T--) work();
return 0;
}