#1956【NOIP2015模拟赛NO.9】vfk的地雷

时间:2022-12-17 12:15:16
概率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;
}