CF2028E 题解

注:定义“上”为根的方向,“下”为叶子的方向。


第一思路是 DP。

\(f_u\) 为从 \(u\) 出发可以逃脱的概率。

  • 如果 Alice 走:她一定要往上走,往下走概率不会变高。

  • 如果 Queen 走:其实她和 Alice 是对称的。她一定要往下走,往上走概率不会变高。

    那她具体去哪个儿子?她应该去最浅的儿子(深度最小的),因为这样 Alice 更可能输。

综上,我们可以知道:

\[f_u = \dfrac{1}{2} (f_v + f_p) \]

其中 \(p\)\(u\) 的父亲,\(v\)\(u\) 最浅的儿子。

我们惊喜的发现这没法转移,所以要变换一下式子。令 \(f_u = k_u f_p + b_u\),则:

\[\begin{aligned} f_u &= \dfrac{1}{2} f_p + \dfrac{1}{2} f_v \\ &= \dfrac{1}{2} f_p + \dfrac{1}{2} (k_v f_u + b_v) \\ &= \dfrac{1}{2} f_p + \dfrac{1}{2} k_v f_u + \dfrac{1}{2} b_v \\ \end{aligned} \]

移项得:

\[\begin{aligned} \left( k_u - \dfrac{1}{2} \right) f_p + b_u &= \dfrac{1}{2} k_v f_u + \dfrac{1}{2} b_v \\ &= \dfrac{1}{2} k_v (k_u f_p + b_u) + \dfrac{1}{2} b_v \\ &= \dfrac{1}{2} k_v k_u f_p + \left( \dfrac{1}{2} k_v b_u + \dfrac{1}{2} b_v \right) \end{aligned} \]

比较系数得:

\[\begin{cases} k_u = \dfrac{1}{2 - k_v} \\ b_u = \dfrac{b_v}{2 - k_v} \end{cases} \]

发现叶子的 \(k_u = b_u = 0\),所以 \(b_u\) 恒为 \(0\),那么 \(f_u = k_u f_p\)

那么 DFS 求 \(k_u\) 后再 DFS 求 \(f_u\) 即可。

#include <bits/stdc++.h>

using namespace std;
using i64 = long long;

constexpr int MOD = 998244353;

inline int add_mod(int x, int y) { return (x + y + MOD) % MOD; }
inline int mul_mod(int x, int y) { return i64(x) * y % MOD; }

int inv_mod(int x)
{
    int y = MOD - 2, res = 1;

    for (; y > 0; y >>= 1, x = mul_mod(x, x)) {
        if (y & 1)
            res = mul_mod(res, x);
    }

    return res;
}

inline int div_mod(int x, int y) { return x == 1 ? inv_mod(y) : mul_mod(x, inv_mod(y)); }

struct Solution {
    int n;
    vector<int> depth, to, fa, k, f; // f[u] = k[u] * f[p]
    vector<vector<int>> tree;

    void solve1(int u)
    {
        for (int v : tree[u]) {
            if (v != fa[u])
                solve1(v);
        }

        int v = to[u];

        if (v != -1)
            k[u] = div_mod(1, add_mod(2, -k[v]));
    }

    void solve2(int u)
    {
        for (int v : tree[u]) {
            if (v == fa[u])
                continue;

            f[v] = mul_mod(k[v], f[u]);
            solve2(v);
        }
    }

    void prep1(int u)
    {
        depth[u] = depth[fa[u]] + 1;

        for (int v : tree[u]) {
            if (v == fa[u])
                continue;

            fa[v] = u;
            prep1(v);
        }
    }

    void prep2()
    {
        queue<pair<int, int>> nodes;

        for (int i = 2; i <= n; ++i) {
            if (tree[i].size() == 1)
                nodes.emplace(i, -1);
        }

        while (!nodes.empty()) {
            auto [curr, from] = nodes.front();
            nodes.pop();

            if (to[curr] == 0)
                to[curr] = from;
            else
                continue;

            nodes.emplace(fa[curr], curr);
        }
    }

    void main()
    {
        cin >> n;
        k.resize(n + 1);
        f.resize(n + 1);
        fa.resize(n + 1);
        to.resize(n + 1);
        tree.resize(n + 1);
        depth.resize(n + 1);

        for (int i = 1; i < n; ++i) {
            int u, v;
            cin >> u >> v;
            tree[u].push_back(v);
            tree[v].push_back(u);
        }

        prep1(1);
        prep2();
        solve1(1);
        f[1] = 1;
        solve2(1);

        for (int i = 1; i <= n; ++i)
            cout << f[i] << ' ';

        cout << '\n';
    }
};

int main()
{
#ifndef ONLINE_JUDGE
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
#endif

    int t;
    cin >> t;

    while (t-- > 0)
        Solution().main();

    return 0;
}
posted @ 2025-08-27 22:57  David9006  阅读(8)  评论(0)    收藏  举报