解析
显然可以利用期望的线性性对每张牌单独计算贡献。
现在的关键就是如何求出每张牌被使用的概率。
考虑第 iii 张牌,如果它的前面 [1,i−1][1,i-1][1,i−1] 中有 jjj 张牌被使用,那么它被使用的概率就是 1−(1−pi)r−j1-(1-p_i)^{r-j}1−(1−pi)r−j。
根据这个,设计 fi,jf_{i,j}fi,j 表示前 iii 张牌中使用了 jjj 张的概率,也不难进行转移:
fi,j=fi−1,j−1(1−(1−pi)r−j+1)+fi−1,j∗(1−pi)r−jf_{i,j}=f_{i-1,j-1}(1-(1-p_i)^{r-j+1})+f_{i-1,j}*(1-p_i)^{r-j}fi,j=fi−1,j−1(1−(1−pi)r−j+1)+fi−1,j∗(1−pi)r−j
求出 fff 后再用其求出每张牌的概率即可。
预处理 (1−pi)k(1-p_i)^k(1−pi)k,时间复杂度 O(Tnr)O(Tnr)O(Tnr)。
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define ok debug("ok\n")
inline ll read(){ll x(0),f(1);char c=getchar(); while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}return f*x;
}const int N=250;
const int mod=1e9+7;int n,m;
double p[N],f[N][N],mi[N][N];
int d[N];
void work(){n=read();m=read();for(int i=1;i<=n;i++) scanf("%lf%d",&p[i],&d[i]); for(int i=1;i<=n;i++){mi[i][0]=1;for(int j=1;j<=m;j++) mi[i][j]=mi[i][j-1]*(1-p[i]);}f[0][0]=1;for(int i=1;i<=n;i++){f[i][0]=f[i-1][0]*mi[i][m];for(int j=1;j<=i;j++){f[i][j]=f[i-1][j-1]*(1-mi[i][m-j+1])+f[i-1][j]*mi[i][m-j];}}double ans(0);for(int i=1;i<=n;i++){for(int j=1;j<=i;j++) ans+=d[i]*f[i-1][j-1]*(1-mi[i][m-j+1]);}printf("%.10lf\n",ans);
}
signed main(){#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);#endifint T=read();while(T--) work();return 0;
}
/*
*/