zoukankan      html  css  js  c++  java
  • GMOJ 6870. 【2020.11.17提高组模拟】ckw的树 (tree)

    ckw的树 (tree)

    一类自己很不会做的题目,还是好好写一写 (所以之前TJ都放在总结里是为了水吗)

    (Description)

    给定一棵包含 (n) 个节点的树,其中 (m) 个点被标记,每单位时间可以从一个点走到距离不超过 (2) 的点中(一条边长度为 (1)),可以走到自己,求从任意点开始走到标记点的期望时间对 (998244353) 取模。


    ( ext{Data Constraint})

    (2 leq n leq 10^5)(1 leq m leq n)


    (Solution)

    设从点 (u) 出发走到标记点的期望时间为 (E(u))

    由于一次转移走到点的距离不能超过 (2),所以 (E(u)) 可以表示成与 (u) 的爷爷、父亲、兄弟、儿子、孙子有关,形式化表达就是:

    [E(u) = frac{aE(gfa_u) + bE(fa_u) + c sum{E(bro(u))} + d sum{E(son(u))} + e sum E(gson(u))}{d_u} + f ]

    其中 ( ext{a, b, c, d, e}) 分别为我们目前并不确定的系数;(d_u) 表示与 (u) 距离不大于 (2) 的节点数;(f) 为同样不确定常数项。

    注意,初始时,(a = b = c = d = e = frac{1}{d_u})(哈这里的 (a, b, c, d, e)((1)) 式有所不同),以及 (f = 1)(表示 (u) 需要一单位时间走到对应节点)

    可以暴力地 (O(n^3)) 高斯消元,分数 (20 sim 40ptes)

    发现式子中 (sum{E(bro(u))})(sum{E(son(u))})(sum{E(gson(u))}) 很难处理,考虑能不能消掉它们。

    首先可以观察到叶子节点是没有 后两项 的,那么我们现在考虑对于节点 (u),其儿子 (v_1, v_2, v_3...) 只有 (a, b, c) 项(为了方便用 (a, b, c) 表示对应的项),该如何消去其 (c) 项。

    同样地可以高斯消元暴力消去,但是时间复杂度上不允许,于是让我们细致地观察式子 (雾),可以得到:

    [sum{E(v_i)} = sum{a_{v_i}E(gfa_{v_i})} + sum{b_{v_i}E(fa_{v_i})} + sum{c_{v_i}sum{E(bro(v_i))}} + sum{f_{v_i}} ]

    其中 (sum{E(v_i)} = sum{E(bro(v_i))})(注意 (v_i in bro(v_i))),(gfa_{v_i} = fa_u)(fa_{v_i} = u),(也就是儿子的 (E(gfa_v)) 相同,(E(fa_v)) 也相同)

    则我们令 (sum{E(bro(v_i))} = sum(u))(sum{a_{v_i}} = A)(sum{b_{v_i}} = B),那么 ((2)) 式可化为:

    [sum(u) = A · E(gfa_v) + B · E(fa_v) + C · sum(u) + sum{f_v} ]

    进一步移项可得:

    [sum{E(bro_v)} = sum(u) = frac{A · E(gfa_v) + B · E(fa_v) + sum{f_v}}{1 - C} ]

    将其代入 (E(v)) 中即可消去 (c) 项。

    那么 (E(son(u)), E(gson(u))) 中就只包含 (a, b) 项了,我们接着思考如何消去 (E(u))(d, e) 项 ((c) 项会在 (fa_u) 处消掉 ),为了方便处理,我们使 ((1)) 式中 (E(u)) 的系数为 (k),初始 (k = 1),然后分类讨论:

    • 对于 (son(u)),其 (gfa = fa_u, fa = u)。同样设 (A = sum{a_v}, B = sum{b_v}, F = sum{f_v}, v in sum(u)),那么若将 (E(son(u))) 代入 (E(u)) 中,(A) 会贡献到 (b_u) 中,(B) 会贡献到 (k)
    • 对于 (gson(u)),其 (gfa = u, fa = son(u))。同上,设 (A = sum{a_{gson(u)}}),若将 (E(gson(u))) 代入 (E(u)) 中,(A) 会贡献到 (k) 中;但与上有区别,对于每个 (v in son(u)),设 (B'_v = sum{b_{v'}}, v' in son(v)),那么每个儿子 (v) 都会带来一个 (B'_v · E(v)) 的项,将 (E(v)) 代入再计算一遍即可。

    为了方便处理,每次处理 (E(u)) 时可以同时计算出 (B'_u = sum{b_v}, v in son(u));以及为了方便以后的处理,最后要将 (k) 变为 (1)

    从下往上处理一遍便得到了所有只包含 (a, b, f) 项的 (E(u)),若以 (1) 为根,那么 (E(1)) 只有 (f) 项,也就是 (E(1)) 已经确定,所以我们只需要从上往下再做一遍,即可求出所有的 (E(u))

    注意标记点的 (E)(0)

    以上语言公式标点可能使用的不太严谨请见谅(明明是炒鸡不严谨好吗),虽然我觉得也只有自己会看这种东东了所以就当是对自己说的吧,,看不懂概不负责(包括自己,再逃)


    (Code)

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    
    #define N 100000
    #define mo 998244353
    
    #define ll long long
    
    #define fo(i, x, y) for(int i = x; i <= y; i ++)
    #define fd(i, x, y) for(int i = x; i >= y; i --)
    #define Fo(i, u) for(int i = head[u]; i; i = edge[i].next)
    
    void read(int &x) {
        char ch = getchar(); x = 0;
        while (ch < '0' || ch > '9') ch = getchar();
        while (ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + ch - 48, ch = getchar();
    }
    
    struct EDGE { int next, to; } edge[N << 1];
    
    int head[N + 1], son[N + 1], d[N + 1], bz[N + 1];
    
    int n, m;
    
    struct Arr { ll a, b, c, d; } f[N + 1], g[N + 1];
    
    int cnt_edge = 1;
    void Add(int u, int v) { edge[ ++ cnt_edge ] = (EDGE) { head[u], v }, head[u] = cnt_edge; }
    void Link(int u, int v) { Add(u, v), Add(v, u); }
    
    ll Fast(ll x, int p = mo - 2) {
        ll res = 1;
        while (p) {
            if (p & 1) (res *= x) %= mo;
            (x *= x) %= mo;
            p >>= 1;
        }
        return res;
    }
    
    void Dfs1(int u, int fa, int ff, int la) {
        d[u] = son[fa] + (fa > 0) + (ff > 0);
        son[u] = 0;
        Fo(i, u) if (i != la) ++ son[u];
        ll A = 0, B = 0, C = 1, D = 0;
        int v = 0;
        Fo(i, u) if (i != la) {
            v = edge[i].to;
            Dfs1(v, u, fa, i ^ 1);
            d[u] += son[v] + 1;
            (A += f[v].a) %= mo, (B += f[v].b) %= mo, (C += mo - f[v].c) %= mo, (D += f[v].d) %= mo;
        }
    
        int sd = Fast(d[u]);
        f[u].a = f[u].b = f[u].c = sd, f[u].d = 1;
        ll K = 1;
    
        ll sc = Fast(C);
        if (! C) sc = 0;
        A = A * sc % mo, B = B * sc % mo, D = D * sc % mo;
        Fo(i, u) if (i != la) {
            v = edge[i].to;
            (f[v].a += f[v].c * A) %= mo;
            (f[v].b += f[v].c * B) %= mo;
            (f[v].d += f[v].c * D) %= mo;
            f[v].c = 0;
    
            (f[u].b += f[v].a * (g[v].b + 1) % mo * sd % mo) %= mo;
            (f[u].d += f[v].d * (g[v].b + 1) % mo * sd % mo) %= mo;
            (K += mo - f[v].b * (g[v].b + 1) % mo * sd % mo) %= mo;
    
            (f[u].d += g[v].d * sd % mo) %= mo;
            (K += mo - g[v].a * sd % mo) %= mo;
    
            (g[u].a += f[v].a) %= mo, (g[u].b += f[v].b) %= mo, (g[u].d += f[v].d) %= mo;
        }
        if (! bz[u]) {
            ll sk = Fast(K);
            (f[u].a *= sk) %= mo, (f[u].b *= sk) %= mo, (f[u].c *= sk) %= mo, (f[u].d *= sk) %= mo;
        } else
            f[u].a = f[u].b = f[u].c = f[u].d = 0;
    }
    
    ll ans[N + 1];
    
    void Dfs2(int u, int fa, int ff, int la) {
        ans[u] = ((f[u].a * ans[ff] % mo + f[u].b * ans[fa] % mo) % mo + f[u].d) % mo;
        Fo(i, u) if (i != la)
            Dfs2(edge[i].to, u, fa, i ^ 1);
    }
    
    int main() {
        freopen("tree.in", "r", stdin);
        freopen("tree.out", "w", stdout);
    
        read(n), read(m);
        int x, y;
        fo(i, 2, n) read(x), read(y), Link(x, y);
        fo(i, 1, m) read(x), bz[x] = 1;
    
        son[0] = 1;
        Dfs1(1, 0, 0, 0);
    
        ll sc = Fast((1 - f[1].c + mo) % mo);
        (f[1].a *= sc) %= mo, (f[1].b *= sc) %= mo, f[1].c = 0, (f[1].d *= sc) %= mo;
        Dfs2(1, 0, 0, 0);
    
        fo(i, 1, n) printf("%d
    ", ans[i]);
    
        return 0;
    }
    
  • 相关阅读:
    java内部类_让你一看就明白_再也不用困惑啦
    hibernate中的java对象有几种状态,其相互关系如何(区别和相互转换)
    未曾谋面却完成了短信发送功能_API是个好中介
    日历(Calendar)_java版(某年的日历,某月的日历)_用户完全自定义
    让你的网站拥有微博(weibo.com)关注图标
    一个demo告诉你优化算法的强大
    给你八分钟搞定dedeCMS(织梦内容管理系统)
    SSL协议(HTTPS) 握手、工作流程详解(双向HTTPS流程)
    oracle数据库:jdbc通用sql分页封装
    浅析HTTP协议
  • 原文地址:https://www.cnblogs.com/zhouzj2004/p/14015812.html
Copyright © 2011-2022 走看看