概率dp就是这样,怎么想都是错的,题解怎么想都想不通,但它就是对的。
期望有些难算,我们还是先算概率。
f[i][j]表示前i个雷,挂了j句话。
那么剩下还有r-j句话,编号1,..,r-j,第k句话挂的概率为(1-p[i])^(k-1)*p[i],所以有话挂的概率为它们的和,即1-(1-p[i])^(r-j),则没话挂的为(1-p[i])^(r-j),记为x
令g[i][j]表示此时的期望贡献,然后大力dp。
详见代码。
看起来很有道理,其实一点都不理解。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#include<cmath>
#include<cstdlib>
#include<bitset>
using namespace std;
#define rep(i,j,k) for(i=j;i<=k;++i)
#define per(i,j,k) for(i=j;i>=k;--i)
#define sqr(x) ((x)*(x))
#define G getchar()
#define LL long long
#define pdi pair<double,int>
#define mkp make_pair
#define X first
#define Y second
#define N 10005
#define NN 50005
double p[221],f[222][133],g[222][133],ans;
int n,m,d[221];
int read(){
int x=0;char ch=G;
while(ch<48||ch>57)ch=G;
for(;ch>47&&ch<58;ch=G)x=x*10+ch-48;
return x;
}
int main(){
int i,j,_;double x;
for(_=read();_--;){
n=read();m=read();
rep(i,1,n){
scanf("%lf",&p[i]);d[i]=read();
}
f[0][0]=1;
rep(i,1,n){
x=1;
per(j,m,0){
f[i][j]+=f[i-1][j]*x;
f[i][j+1]+=f[i-1][j]*(1-x);
g[i][j]+=g[i-1][j]*x;
g[i][j+1]+=(g[i-1][j]+d[i]*f[i-1][j])*(1-x);
x*=(1-p[i]);
}
}
ans=0;
rep(i,1,m)ans+=g[n][i];
printf("%.10lf\n",ans);
}
return 0;
}