关于连续型随机变量的期望问题
定义
连续随机型变量的期望问题指的是:
对于一个连续型随机变量 \(X\) ,以及一个函数 \(f(x)=P[x==X]\) ,求 \(E(X)\) 的问题。
解法:
若 \(X\) 是一个离散型的随机变量,可能值为 \(x_1,x_2…\),对应的概率分别为 \(p_1,p_2…\),那么它的期望值就是 \(E(x)=∑_ip_ix_i\)。
类似地,仍然考虑离散随机变量 \(X\) ,令它有 \(n\) 个取值 \(0,δ,2δ,3δ,…,(n−1)δ\) ,其中 \(δ\) 满足 \(δ=\frac{M}{n}\) ,且 \(M\) 为常数。那么它的期望就是:
考虑 \(n→+∞\) 的时候,可以发现:
由于 \(X\) 的取值被限制在 \([0,M)\) 里面,所以积分上界也可以被修改。
我们也可以通过几何意义来证明,期望相当于对所有等可能情况取平均值。
那么把 \(P(x<X)\) 的函数图像画出来,就是要求图像上每一点到 \(x\) 轴的距离的平均值,也就是函数面积除以以定义域大小。
#1178. 星际旅行
这题让我们求的是概率,因此我们只需要求 \(P(x==X)\) 图像上每一点到 \(x\) 轴的平均距离。
我们发现这个概率是一个分段函数,在一段区间 \([i,i+1)\) 中,一个物品被吸附的概率是一个特定的一次函数,我们只需像处理离散型随机变量时那样做背包,即可对每个 \(k\) 求出吸附 \(k\) 个物品的概率在这个区间内的函数。
对这个函数积分,转化原函数的面积公式:\(\int_{i}^{i+1}f(x)=\int_{0}^{i+1}f(x)-\int_{0}^{i}f(x)\),算出所有面积后除以定义域 \(L\) 即为平均高度。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n,L;
int a[35],b[35];
using poly=vector<long double>;
inline poly operator +(poly a,poly b){
if(a.size()<b.size())swap(a,b);
for(int i=0;i<b.size();i++)a[i]+=b[i];
return a;
}
inline poly operator -(int a,poly b){
if(b.empty())b.resize(1);
for(auto &it:b)it=-it;b[0]+=a;
return b;
}
inline poly operator *(poly a,poly b){
poly res(a.size()+b.size()-1);
for(int i=0;i<a.size();i++){
for(int j=0;j<b.size();j++)res[i+j]+=a[i]*b[j];
}
return res;
}
inline poly Integral(poly a){
poly res(a.size()+1);
for(int i=1;i<res.size();i++)res[i]=a[i-1]/i;
return res;
}
inline long double Get(int x,poly f){
long double res=0;
for(int i=f.size()-1;~i;i--)res=res*x+f[i];
return res;
}
poly dp[35];
long double ans[35];
int main(){
scanf("%d%d",&n,&L);
for(int i=1;i<=n;i++){
int x;scanf("%d%d%d",&x,&a[i],&b[i]);
}
for(int t=0;t<L;t++){
for(int i=0;i<=n;i++)dp[i].clear();
dp[0]={1};
for(int i=1;i<=n;i++){
poly p;
if(a[i]<=t&&t+1<=a[i]+b[i])p={1+1.0*a[i]/b[i],-1.0/b[i]};
else if(a[i]-b[i]<=t&&t+1<=a[i])p={1-1.0*a[i]/b[i],1.0/b[i]};
else continue;
for(int j=n;j;j--)dp[j]=(1-p)*dp[j]+p*dp[j-1];
dp[0]=dp[0]*(1-p);
}
for(int i=0;i<=n;i++)dp[i]=Integral(dp[i]);
for(int i=0;i<=n;i++)ans[i]+=Get(t+1,dp[i])-Get(t,dp[i]);
}
long double E=0;
for(int i=0;i<=n;i++)ans[i]/=L;
for(int i=0;i<=n;i++)E+=i*ans[i];
printf("%Lf\n",E);
for(int i=0;i<=n;i++)printf("%Lf ",ans[i]);
return 0;
}
ARC113F Social Distance
给一个长度为 \(n+1\) 的正整数序列 \(x\),保证 \(x_{0}=0\) 且 \(x\) 递增。
现在随机生成一个长度为 \(n\) 的实数序列 \(y\),其中 \(y_{i}\) 在 \(\left[x_{i-1}, x_{i}\right]\) 间随机生成。 定义序列 \(y\) 的权值为 \(\min _{i=1}^{n-1}\left(y_{i}-y_{i-1}\right)\),求 \(y\) 权值的期望,模 \(998244353\) 。
\(n \leq 20\)
\(4 s, 1024 \text{MB}\)
设 \(f(v)\) 表示权值大于等于 \(v\) 的概率,答案即为 \(\int_{v=0}^{+\infty} f(v) dv\) 。
考虑如何计算一个 \(f(v)\) ,问题相当于 \(y_{i}\) 在 \(\left[x_{i-1}, x_{i}\right]\) 中随机生成,求 \(\forall i, y_{i}+v \leq y_{i+1}\) 的概率.考虑令 \(b_{i}=y_{i}-i * v\) ,则相当于 \(b_{i}\) 在 \(\left[x_{i-1}-i v, x_{i}-i v\right]\) 中随机生成,求 \(\forall i, b_{i} \leq b_{i+1}\) 的概率。
考虑将概率乘上 \(\prod_{i}\left(x_{i}-x_{i-1}\right)\) ,这相当于将 \(b_{i}\) 在 \(\left[x_{i-1}-i v, x_{i}-i v\right]\) 出现的概率分布都是 \(1\) 。
按照所有的区间端点将值域划分成 \(2 k\) 段,按照值从小到大排序,考虑枚举每个点的取值属于哪一段,则值所在的段编号一定不降。考虑一段内的情况,设一段长度为 \(l\) ,且有 \(k\) 个数取值在这一段内。可以考虑设 \(dp_{i, j, k}\) 表示考虑了前 \(i\) 个元素,当前第 \(i\) 个元素的值在第 \(j\) 段内,前面一共有 \(k\) 个元素在这一段内时,前面的所有情况贡献和。这样可以 \(O\left(n^{3}\right)\) 求出一个 \(f(v)\) ,这里还有很多不同的 \(dp\) 方式。
考虑 \(v\) 变化的情况,此时可以将所有边界看成关于 \(v\) 的一次函数,因此如果 \(v \in[l, r]\) 时,所有端点间的大小顺序不发生改变,则这一段内的 \(\mathrm{dp}\) 转移相同。在 \(\mathrm{dp}\) 时维护关于 \(v\) 的多项式,可以发现单次复杂度变为 \(O\left(n^{4}\right)\) 。
同时因为所有边界都是一次函数,可以发现大小顺序发生改变的次数为 \(O\left(n^{2}\right)\) ,因此对于每一段分别求贡献即可。
复杂度 \(O\left(n^{6}\right)\) 。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n;
const int md=998244353;
inline int pwr(int x,int y){
int res=1;
while(y){
if(y&1)res=1ll*res*x%md;
x=1ll*x*x%md;y>>=1;
}
return res;
}
struct frac{
int m,d;
frac(int _m,int _d){
m=_m;d=_d;
}
inline bool operator==(const frac &b)const{
return m==b.m&&d==b.d;
}
inline bool operator<(const frac &b)const{
return m*b.d<b.m*d;
}
inline operator int(){
return 1ll*m*pwr(d,md-2)%md;
}
};
struct point{
int b,k,id;
point(int _b,int _k,int _id){
b=_b;k=_k;id=_id;
}
inline frac operator()(const frac &y)const{
return frac(b*y.d-k*y.m,y.d);
}
};
int x[25],w[55],inv[25],ifac[25];
inline void init(){
inv[0]=inv[1]=ifac[0]=ifac[1]=1;
for(int i=2;i<=n+1;i++)inv[i]=1ll*(md-md/i)*inv[md%i]%md;
for(int i=2;i<=n+1;i++)ifac[i]=1ll*ifac[i-1]*inv[i]%md;
}
typedef vector<int> poly;
poly operator+(poly a,poly b){
if(a.size()<b.size())swap(a,b);
poly c=a;
for(int i=0;i<b.size();i++)c[i]=(c[i]+b[i])%md;
return c;
}
poly operator*(const poly& a,const poly& b){
poly c(a.size()+b.size()-1);
for(int i=0;i<a.size();i++)
for(int j=0;j<b.size();j++)c[i+j]=(c[i+j]+1ll*a[i]*b[j]%md)%md;
return c;
}
poly operator*(const poly& a,int b){
poly c(a.size());
for(int i=0;i<a.size();i++)c[i]=1ll*a[i]*b%md;
return c;
}
poly integral(const poly& a){
poly c(a.size()+1);
for(int i=1;i<c.size();i++)c[i]=1ll*a[i-1]*inv[i]%md;
return c;
}
int getval(const poly& a,int x){
int x2=1,res=0;
for(int i=0;i<a.size();i++)res=(res+1ll*a[i]*x2%md)%md,x2=1ll*x2*x%md;
return res;
}
poly f[55][25];
int main(){
scanf("%d",&n);init();
for(int i=0;i<=n;i++)scanf("%d",&x[i]);
vector<point>p;
for(int i=1;i<=n;i++)p.emplace_back(x[i-1],i-1,2*i-1),p.emplace_back(x[i],i-1,2*i);
vector<frac>t;
for(int i=0;i<2*n;i++)
for(int j=i+2-(i & 1);j<2*n;j++)t.emplace_back(p[j].b-p[i].b,p[j].k-p[i].k);
sort(t.begin(),t.end()),t.erase(unique(t.begin(),t.end()),t.end());
int ans=0;
for(int nt=0;nt<t.size()-1;nt++){
auto cmp=[&](const point& a,const point& b){
if(a(t[nt])==b(t[nt]))return a.k>b.k;
return a(t[nt])<b(t[nt]);
};
sort(p.begin(),p.end(),cmp);
for(int i=0;i<p.size();i++)w[p[i].id]=i;
f[0][0]={1};
for(int i=1;i<p.size();i++){
for(int j=0;j<=n;j++){
f[i][j].clear();
poly z={(p[i].b-p[i-1].b+md)%md,(p[i-1].k-p[i].k+md)%md},z2=z;
for(int k=1;k<=j;k++){
int nid=j-k+1,L=w[2*nid-1],R=w[2*nid]-1;
if(L>i-1||i-1>R)break;
f[i][j]=f[i][j]+f[i-1][nid-1]*z*ifac[k];
z=z*z2;
}
f[i][j]=f[i][j]+f[i-1][j];
}
}
poly g=integral(f[p.size()-1][n]);
ans=(ans+(getval(g,t[nt+1])-getval(g,t[nt])+md)%md)%md;
}
for(int i=1;i<=n;i++)ans=1ll*ans*pwr(x[i]-x[i-1],md-2)%md;
printf("%d",ans);
return 0;
}