​传送门啊​

定义 f [ x ] f[x] f[x]是 x x x向父亲走一步的期望步数

f [ x ] = 1 i n [ x ] + 1 i n [ x ] ∑ v ∈ s o n ( f [ v ] + f [ x ] + 1 ) f[x]=\frac{1}{in[x]}+\frac{1}{in[x]}\sum\limits_{v\in son}(f[v]+f[x]+1) f[x]=in[x]1+in[x]1v∈son∑(f[v]+f[x]+1)

意思是走到父节点概率是 1 i n [ x ] , 走 到 儿 子 那 么 还 需 要 走 回 来 \frac{1}{in[x]},走到儿子那么还需要走回来 in[x]1,走到儿子那么还需要走回来

稍稍变形可得

f [ x ] = 1 + 1 i n [ x ] ∑ v ∈ s o n f [ v ] + i n [ x ] − 1 i n [ x ] f [ x ] f[x]=1+\frac{1}{in[x]}\sum\limits_{v\in son}f[v]+\frac{in[x]-1}{in[x]}f[x] f[x]=1+in[x]1v∈son∑f[v]+in[x]in[x]−1f[x]

f [ x ] = i n [ x ] + ∑ v ∈ s o n f [ v ] f[x]=in[x]+\sum\limits_{v\in son}f[v] f[x]=in[x]+v∈son∑f[v]

那么可以一遍 d f s dfs dfs求解 f f f数组

那么对于每个 x x x,有 s i z [ x ] siz[x] siz[x]个点需要走 f [ x ] f[x] f[x]

然后枚举每个点作为终点,即可求得答案,复杂度 O ( n 2 ) O(n^2) O(n2)

​50分代码​

但是这样不够快

我们发现 f [ x ] f[x] f[x]其实就是子树内度数的和

当 终 点 在 x 时 , 不 需 要 计 算 f [ x ] 当终点在x时,不需要计算f[x] 当终点在x时,不需要计算f[x]

当 终 点 不 在 x 子 树 内 时 , 有 n − s i z [ x ] 种 可 能 , 每 种 贡 献 是 s i z [ x ] ∗ f [ x ] 当终点不在x子树内时,有n-siz[x]种可能,每种贡献是siz[x]*f[x] 当终点不在x子树内时,有n−siz[x]种可能,每种贡献是siz[x]∗f[x]

当 终 点 在 x 的 某 个 儿 子 v 内 部 时 , 有 s i z [ v ] 种 可 能 , 每 种 当终点在x的某个儿子v内部时,有siz[v]种可能,每种 当终点在x的某个儿子v内部时,有siz[v]种可能,每种

贡 献 是 ( n − s i z [ v ] ) ∗ ( 总 度 数 − v 子 树 内 的 度 数 ) 贡献是(n-siz[v])*(总度数-v子树内的度数) 贡献是(n−siz[v])∗(总度数−v子树内的度数)

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=2e5+10;
const int mod=998244353;
struct edge{
int to,nxt;
}d[maxn]; int head[maxn],cnt=1;
void add(int u,int v)
{
d[++cnt]=(edge){v,head[u]},head[u]=cnt;
}
int quick_pow(int x,int n)
{
int ans=1;
while( n )
{
if( n&1 ) ans = ans*x%mod;
x=x*x%mod;
n>>=1;
}
return ans;
}
int n,siz[maxn],ans,kkk,in[maxn],f[maxn],invn,root;
void dfs(int u,int fa)
{
siz[u]=1;
for(int i=head[u];i;i=d[i].nxt )
{
int v=d[i].to; if( v==fa ) continue;
dfs(v,u); siz[u]+=siz[v];
in[u]+=in[v];
}
for(int i=head[u];i;i=d[i].nxt )
{
int v=d[i].to;
if( v==fa ) ans = (ans+(n-siz[u])*in[u]%mod*siz[u]%mod )%mod;
else ans = (ans+siz[v]*(2*n-2-in[v])%mod*(n-siz[v])%mod )%mod;
}
}
signed main()
{
cin >> n;
for(int i=1;i<n;i++)
{
int l,r; cin >> l >> r;
add(l,r); add(r,l);
in[l]++,in[r]++;
}
invn=quick_pow(n*n%mod,mod-2);
dfs(1,0);
cout << ans*invn%mod;
}