经典套路为 。考虑先求 的期望:显然有 ,可以前缀和优化。
问题在于计算 ()的期望。因为 所以 。考虑模拟不加优化的 计算的过程:每一次把 移动到父亲结点,直到 。考虑到 在 中等概率选取,因此假设 跳到了 ,则 时落到的结点取 的概率相等。否则令 然后此时仍有 因此返回第一步。容易发现最终 落在 的概率是相同的。
因此证明了 。此时 的值和 无关只和 有关,但是仍然没有计算出其实际的期望值。此时考虑 dp,设 表示最后 的深度的期望。则显然有递推公式:,同样可以前缀和处理。于是做完了。线性处理逆元可以做到 通过。注意最后答案需要乘以 。
#pragma GCC optimize(3,"Ofast","inline")
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1000010;
const int mod=998244353;
const int inf=1e18;
vector<int>adj[N];
int inv[N],f[N],dep[N],pre[N],a[N],fac[N];
signed main(){
cin.tie(0)->sync_with_stdio(false);
int n,m;cin>>n>>m;
for(int i=2;i<=n;++i)cin>>a[i];
inv[0]=inv[1]=1;
fac[0]=1;
for(int i=1;i<N;++i)fac[i]=fac[i-1]*i%mod;
for(int i=2;i<N;++i)inv[i]=mod-inv[mod%i]*(mod/i)%mod;
dep[1]=0;
for(int i=2;i<=n;++i){
dep[i]=(pre[i-1]*inv[i-1]%mod)+a[i];
dep[i]%=mod;
pre[i]=(pre[i-1]+dep[i])%mod;
}
f[1]=0;
for(int i=2;i<=n;++i){
f[i]=(dep[i]+pre[i-1])*inv[i]%mod;
pre[i]=(pre[i-1]+f[i])%mod;
}
while(m--){
int a,b;cin>>a>>b;
cout<<(dep[a]+dep[b]-2*f[a]%mod+mod+mod)%mod*fac[n-1]%mod<<'\n';
}
}
喜欢的话,留下你的评论吧~