考虑算概率最后乘上d,因为直接计算每张卡每轮的概率不现实(无法转移),所以考虑一个整体并且可以表示出每张卡的状态,
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示
m
m
m轮中前
i
i
i张卡用了
j
j
j张的概率,则要表示一张卡
i
i
i在
m
m
m轮中出现过的概率就是
f
[
i
−
1
]
[
j
]
f[i-1][j]
f[i−1][j]乘上必须选
i
i
i的概率,不选
i
i
i的概率就是在后面
m
−
j
m-j
m−j轮中都跳过了
i
i
i的概率,就是
(
1
−
p
[
i
]
)
m
−
j
(1-p[i])^{m-j}
(1−p[i])m−j,用1减去不选的概率就是选的概率
然后转移就是考虑选不选
i
i
i,选不选
i
i
i的概率就如上面所述,方程为
f
[
i
]
[
j
]
=
f
[
i
−
1
]
[
j
]
∗
(
1
−
p
[
i
]
)
m
−
j
+
f
[
i
−
1
]
[
j
−
1
]
∗
(
1
−
(
1
−
p
[
i
]
)
m
−
j
+
1
)
)
f[i][j]=f[i-1][j]*(1-p[i])^{m-j}+f[i-1][j-1]*(1-(1-p[i])^{m-j+1}))
f[i][j]=f[i−1][j]∗(1−p[i])m−j+f[i−1][j−1]∗(1−(1−p[i])m−j+1))
Code:
#include<bits/stdc++.h>
#define db double
using namespace std;
inline int read(){
int res=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
return res*f;
}
const int N=225;
inline db ksm(db a,int b){db res=1.0;for(;b;b>>=1,a*=a) if(b&1) res*=a;return res;}
db f[N][N],p[N];
int d[N];
int n,m;
int main(){
int t=read();
while(t--){
memset(f,0,sizeof(f));
n=read();m=read();
for(int i=1;i<=n;++i){
scanf("%lf",&p[i]);
d[i]=read();
}
f[0][0]=1;
for(int i=1;i<=n;++i)
for(int j=0;j<=min(i,m);++j){
if(!j) f[i][j]=f[i-1][j]*ksm(1-p[i],m-j);
else f[i][j]=f[i-1][j]*ksm(1-p[i],m-j)+f[i-1][j-1]*(1-ksm(1-p[i],m-j+1));
}
db res=0;
for(int i=1;i<=n;++i){
db now=0;
for(int j=0;j<=min(i-1,m);++j) if(j!=m) now+=f[i-1][j]*(1-ksm(1-p[i],m-j));
res+=now*d[i];
}
printf("%.10lf\n",res);
}
return 0;
}
本文深入解析了BZOJ4008题目的算法思路,通过动态规划的方法,计算了多轮游戏中特定卡片出现的概率,并最终求得期望值。详细介绍了状态转移方程的推导过程及其实现代码。
422

被折叠的 条评论
为什么被折叠?



