AtCoder [ARC195E]. Random Tree Distance

题目需要求 $(u, v)$ 路径长度总和,这是不好解决的,所以考虑转化为期望,最后再乘 $(n-1)!$。
根据期望的线性性,就可以设 $f_i$ 表示 $i$ 的期望深度,那么答案就为 $f_u + f_v - 2 f_{lca(u,v)}$。
前两者是好做的,因为根据定义显然有转移式 $f_i = a_i + \frac{1}{i-1} \sum\limits_{j=1}^{i-1} f_j$。
但是 $lca$ 这件事就很麻烦,因为树的形态不同 $lca$ 也不相同。


实际上 $lca(u,v)$ 的期望深度只和 $u$ 有关
考虑钦定 $u \lt v$,可以让 $v$ 不断往上跳直到发现 $v$ 的父亲编号 $\leq u$。
下一步显然 $v$ 跳到 $1 \leq t \leq u$ 中任意一个点 $t$ 的概率是均等的。
而且观察到前半部分跳跃和后半部分跳跃是独立的,因此 $lca$ 的期望深度只和 $u$ 有关,并且 $lca(u,v) = lca(u,u+1)$。


设 $g_u$ 表示固定 $u$ 之后,$lca(u,v)$ 的期望深度。
要么 $u$ 作为 $lca$,要么再往前的点作为 $lca$。
因此有转移式 $g_u = \frac{ f_u + \sum\limits_{i=1}^{u-1} g_i }{u}$。

记得乘阶乘。

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 15, mod = 998244353;

int qmi(int a, int k) {
    int res = 1;
    while (k) {
        if (k & 1) res = res * 1ll * a % mod;
        a = a * 1ll * a % mod;
        k >>= 1;
    }
    return res;
}
int inv(int x) { return qmi(x, mod - 2); }

int n, m, a[N], f[N], g[N];
int main() {
    scanf("%d%d", &n, &m);
    for (int i = 2; i <= n; i++) scanf("%d", &a[i]);
    long long sumf = 0, sumg = 0, mul = 1;
    for (int i = 2; i < n; i++) (mul *= i) %= mod;
    for (int i = 2; i <= n; i++) f[i] = ( a[i] + (sumf * 1ll * inv(i - 1) % mod) ) % mod, (sumf += f[i]) %= mod;
    for (int i = 2; i <= n; i++) g[i] = (f[i] + sumg) * 1ll * inv(i) % mod, (sumg += g[i]) %= mod;
    while (m--) {
        int u, v; scanf("%d%d", &u, &v);
        if (u > v) swap(u, v);
        if (u ^ v) printf("%d\n", ( (f[u] + f[v] - 2 * g[u]) % mod + mod ) * 1ll * mul % mod);
        else puts("0");
    }
    return 0;
}
posted @ 2025-03-24 20:51  Conan15  阅读(9)  评论(0)    收藏  举报  来源