「方差期望」学习记录
之前联考模拟赛一道题,感觉推式子很干(我又太菜不会推),但是最后很有意思(?)。记录一下。
- 题目大意
有 \(n\) 个物体,第 \(i\) 个出现的概率是 \(p_i\) 。记其第一次出现时间是 \(t_i\) 。求 \(t_i\) 方差的期望值。
- 分析
开始大力推式子。
注意到 \(t_i\) 与 \(t_j\) 不是相互独立的。所以不能拆开算。
因为我们需要计算 \(\operatorname{E}(t_i^2)\) 与 \(\operatorname{E}(t_it_j)\) 。
又因为 \(i^2=1+3+5+...\)
所以每个 \(i\) 会对 \(1,3,5,7,...\) 贡献 \((1-p_i)^{i-1}p_i\) 。
逆向考虑,考虑每个位置有多少个 \(i\) 对其有贡献。
不妨设 \(s=\sum\limits_{j\ge 0}j(1-p_i)^j\) ,则
解得 \(s=\dfrac{1}{p_i^2}-\dfrac{1}{p_i}\) ,故 \(\operatorname{E}(t_i^2)=\dfrac{2-p_i}{p_i^2}\) 。
接下来是 \(2\operatorname{E}(t_it_j)\) 。
考虑 \(2\operatorname{E}(t_it_j)=\operatorname{E}(t_i^2)+\operatorname{E}(t_j^2)-\operatorname{E}((t_i-t_j)^2)\) 。
变相理解,记第 \(i\) 个物品和第 \(j\) 个物品出现时间差的平方的期望。不妨设 \(f_{i,j}\) 表示 \(i\) 比 \(j\) 前出现的概率。
所以 \(\operatorname{E}((t_i-t_j)^2)=f_{i,j}\operatorname{E}(t_j^2)+f_{j,i}\operatorname{E}(t_i^2)\) ,
得
考虑 \(f_{i,j}\) 的转移
所以得
其中 \(p_i+p_j\) 的逆元用类似前缀和一样的求法预处理。
复杂度 \(\mathcal{O}(n^2)\) 。
\(10^5\) 做法要多点插值,暂鸽。
- 代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
const ll N=5000+5;
const ll Mod=998244353;
ll n,sum,inv,a[N],p[N],E[N];
ll ans1,ans2,iv[N],pre[N][N],ipre[N][N];
ll qpow(ll x,ll k)
{ ll res=1;
while(k)
{ if(k&1)res=res*x%Mod;
x=x*x%Mod;
k>>=1;
}
return res;
}
ll f(ll x,ll y)
{ if(x>y)return ipre[y][x]*pre[y][x-1]%Mod*p[x]%Mod;
return ipre[x][y]*pre[x][y-1]%Mod*p[x]%Mod;
}
int main()
{ freopen("card.in","r",stdin);
freopen("card.out","w",stdout);
scanf("%lld",&n);
for(ll i=1;i<=n;i++)
{ scanf("%lld",&a[i]);
sum=(sum+a[i])%Mod;
}
inv=qpow(sum,Mod-2)%Mod;
for(ll i=1;i<=n;i++)
{ p[i]=a[i]*inv%Mod;
iv[i]=qpow(p[i],Mod-2);
E[i]=(2-p[i]+Mod)%Mod*iv[i]%Mod*iv[i]%Mod;
}
for(ll i=1;i<=n;i++)ans1=(ans1+iv[i])%Mod;
ans1=ans1*qpow(n,Mod-2)%Mod;
printf("%lld\n",ans1);
for(ll i=1;i<=n;i++)
{ pre[i][i]=1;
for(ll j=i+1;j<=n;j++)
pre[i][j]=(p[i]+p[j])%Mod*pre[i][j-1]%Mod;
ipre[i][n]=qpow(pre[i][n],Mod-2);
for(ll j=n-1;j>=i;j--)
ipre[i][j]=(p[i]+p[j+1]%Mod)*ipre[i][j+1]%Mod;
}
inv=qpow(n,Mod-2)%Mod;
for(ll i=1;i<=n;i++)
{ ans2=(ans2+(n-1)*inv%Mod*inv%Mod*E[i]%Mod)%Mod;
for(ll j=i+1;j<=n;j++)
{ ans2=(ans2-f(i,j)*E[i]%Mod*inv%Mod*inv%Mod+Mod)%Mod;
ans2=(ans2-f(j,i)*E[j]%Mod*inv%Mod*inv%Mod+Mod)%Mod;
}
}
printf("%lld\n",ans2);
return 0;
}