Problem
Solution
这题真心不会,Orz题解
大概讲一下吧:
考虑每一张牌用过后不可用了,所以考虑每一张牌在 r r 轮中使用的概率是比较可行的,最后所有牌的概率与伤害乘积和即为期望答案
那么设第张牌使用的概率为 fp[x] f p [ x ] ,在 r r 轮中前张牌中使用 j j 张的概率为
方程:
f[i][j]=f[i−1][j]·(1−p[i])r−j+f[i−1][j−1]·(1−(1−p[i])r−j+1)
f
[
i
]
[
j
]
=
f
[
i
−
1
]
[
j
]
·
(
1
−
p
[
i
]
)
r
−
j
+
f
[
i
−
1
]
[
j
−
1
]
·
(
1
−
(
1
−
p
[
i
]
)
r
−
j
+
1
)
前面一项是当前一项不选, f[i−1][j] f [ i − 1 ] [ j ] 表示前 i−1 i − 1 张中已经使用了 j j 张牌,所以当前的牌在接下来的轮中始终不选,概率为 (1−p[i])r−j ( 1 − p [ i ] ) r − j
后面的一项是当前一项选,由于选取了这一张,所以要考虑后面剩下的 r−j+1 r − j + 1 轮还没考虑,所以转移概率为 1−(1−p[i])r−j+1 1 − ( 1 − p [ i ] ) r − j + 1
对于
fp[]
f
p
[
]
:
fp[i]=∑j=0rf[i−1][j]·(1−(1−p[i])r−j)
f
p
[
i
]
=
∑
j
=
0
r
f
[
i
−
1
]
[
j
]
·
(
1
−
(
1
−
p
[
i
]
)
r
−
j
)
这个式子大意是求在每一轮中出现的概率相加
最后统计答案:
ans=∑i=1nfp[i]·d[i]
a
n
s
=
∑
i
=
1
n
f
p
[
i
]
·
d
[
i
]
Code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rg register
#define cl(x) memset(x,0,sizeof(x))
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define abs(x) ((x)>0?(x):(-(x)))
template <typename _Tp> inline _Tp read(_Tp&x){
rg char c11=getchar(),ob=0;x=0;
while(c11^'-'&&!isdigit(c11))c11=getchar();if(c11=='-')c11=getchar(),ob=1;
while(isdigit(c11))x=x*10+c11-'0',c11=getchar();if(ob)x=-x;return x;
}
const int N=400;
double a[N],p[N],fp[N],mi[N][N],f[N][N];
int n,r;
int main(){
int T;read(T);while(T--){
cl(f),cl(fp);
read(n),read(r);
for(rg int i=1;i<=n;++i)scanf("%lf%lf",&p[i],&a[i]);
for(rg int i=1;i<=n;++i){
mi[i][0]=1;
for(rg int j=1;j<=r;++j)
mi[i][j]=mi[i][j-1]*(1.0-p[i]);
}
f[1][0]=mi[1][r];
f[1][1]=fp[1]=1-f[1][0];
for(rg int i=2;i<=n;++i)
for(rg int j=0;j<=min(r,i);++j){
fp[i]+=f[i-1][j]*(1-mi[i][r-j]);
f[i][j]+=f[i-1][j]*mi[i][r-j];
if(j)f[i][j]+=f[i-1][j-1]*(1-mi[i][r-j+1]);
}
double ans=0.0;
for(rg int i=1;i<=n;++i)ans+=a[i]*fp[i];
printf("%.10lf\n",ans);
}
return 0;
}