码迷,mamicode.com
首页 > 其他好文 > 详细

「十二省联考 2019」希望

时间:2020-06-01 20:46:48      阅读:50      评论:0      收藏:0      [点我收藏+]

标签:splay   就是   连通块   tor   %x   problem   答案   span   void   

「十二省联考 2019」希望

下面全是口胡

传送门

Loj

题解

暴力

首先考虑一个暴力的\(dp\),设\(f_{u,i}\)表示以\(u\)为根的子树,最长的长度不超过\(j\)的连通块个数,\(g_{u,i}\)表示\(u\)子树外的长度不超过\(i\)的连通块个数.这个时候有:

\[f_{u,i}=\prod_{v\in son_u}(f_{v,i-1}+1) \g_{u,i}=g_{fa,i-1}\prod_{v \in son_{fa},v\ne u}f_{v,i-2}+1 \]

然后答案考虑容斥,如果你对于每一个\(u\)计算\(f_{u,L}*g_{u,L}\),会算重复一些连通块,那么根据如下事实:

连通块的交还是一个连通块,我们可以想到一个容斥,即:点的贡献-边的贡献就是答案.

所以答案为:\((f_{u,L}*g_{u,L})^k-(f_{u,L-1}*(g_{u,L}-1))^k\)

优化

接下来考虑怎么优化这个求\(f\)\(g\)的过程.

\(f_{u,i} \rightarrow f_{u,i}+1\),那么这就是一个长链剖分转移\(dp\),然后打一个全局标记.

但是这个时候不会转移\(len_v\)以后的数字,这个时候要给全局打一个乘法标记,然后对前面打一个逆元的乘法.

计算\(g\)你需要考虑暴力计算下,我们可以通过前后缀积计算.

长链剖分下,我们还是可以计算前缀积,后缀积考虑用一个回退数据结构维护即可.

代码

把儿子的代码贴过来

#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <list>
#include <algorithm>
#define ll long long
#define Add(a, b) (a + b + Mod) % Mod
#define Mul(a, b) 1ll * a *b % Mod
#define Assign(x)     (f[x] = pf, pf += T.len[x] + 2, pg += T.len[x] + 2, g[x] = pg - max(L - T.len[x], 0), pg += T.len[x] + 2)
#define Gmin(x, y) (x > (y) && (x = (y)))
using namespace std;

inline int read() {
    int sum = 0, f = 1;
    char c = getchar();
    while (c > ‘9‘ || c < ‘0‘) {
        if (c == ‘-‘)
            f = -1;
        c = getchar();
    }
    while (c <= ‘9‘ && c >= ‘0‘) {
        sum = sum * 10 + c - ‘0‘;
        c = getchar();
    }
    return f * sum;
}

const int N = 1000005;
const int Mod = 998244353;
struct edge {
    int to, next;
} e[N << 1];
int n, L, K, ans;
int head[N], cnt;
int _f[N << 4], _g[N << 4], *f[N], *g[N], *pf = _f, *pg = _g;

inline void add(int x, int y) {
    e[++cnt] = (edge){ head[x], y };
    head[x] = cnt;
}

inline ll fpow(ll a, ll b) {
    ll ret = 1;
    while (b) {
        if (b & 1)
            ret = Mul(ret, a);
        a = Mul(a, a);
        b >>= 1;
    }
    return ret;
}

struct pre {
    int s[N], len[N], u[N], w[N], inv[N];
    vector<int> B[N], S[N];
    inline void dfs(int x, int fa) {
        inv[x] = 1;
        for (int i = head[x]; i; i = e[i].to) {
            int k = e[i].next;
            if (k == fa)
                continue;
            dfs(k, x);
            if (len[k] > len[s[x]])
                s[x] = k;
            inv[x] = Mul(inv[x], inv[k]);
        }
        len[x] = len[s[x]] + 1;
        inv[x] = Add(inv[x], 1);
        if (!s[x])
            return;
        int maxn = 0;
        for (int i = head[x]; i; i = e[i].to) {
            int k = e[i].next;
            if (k == fa || k == s[x])
                continue;
            B[len[k]].push_back(k);
            maxn = max(maxn, len[k]);
        }
        for (int i = maxn; i >= 0; i--) {
            for (int j = 0, mx = B[i].size(); j < mx; j++) S[x].push_back(B[i][j]);
            B[i].clear();
        }
    }
    inline void init() {
        int tot = 0;
        len[0] = -1;
        dfs(1, 0);
        w[0] = 1;
        for (int i = 1; i <= n; i++)
            if (inv[i])
                u[++tot] = i, w[tot] = Mul(w[tot - 1], inv[i]);
        w[tot] = fpow(w[tot], Mod - 2);
        for (int i = tot; i; i--) {
            int x = inv[u[i]];
            inv[u[i]] = Mul(w[i], w[i - 1]);
            w[i - 1] = Mul(w[i], x);
        }
    }
} T;

struct back {
    struct pr {
        int *w, v;
    };
    list<pr> t;
    inline void ins(int &x) { t.push_back((pr){ &x, x }); }
    inline void reset() {
        while (!t.empty()) *(t.back().w) = t.back().v, t.pop_back();
    }
} S[N];

struct fff {
    int mul[N], imul[N], add[N], lim[N], zero[N];
    inline int gv(int x, int p) {
        return Gmin(p, T.len[x]), Add(1LL * mul[x] * (p < lim[x] ? f[x][p] : zero[x]) % Mod, add[x]);
    }
    inline int giv(int x, int v) { return Mul(imul[x], Add(v, -add[x])); }
    inline void dfs(int x, int fa) {
        int ls = T.s[x];
        if (!ls) {
            lim[x] = mul[x] = imul[x] = add[x] = 1;
            //	add[x]=Add(add[x],1);//return ;
            goto End;
        }
        f[T.s[x]] = f[x] + 1;
        dfs(T.s[x], x);
        mul[x] = mul[T.s[x]];
        imul[x] = imul[T.s[x]];
        add[x] = add[T.s[x]];
        zero[x] = zero[T.s[x]];
        lim[x] = lim[T.s[x]] + 1;
        f[x][0] = giv(x, 1);
        for (int i = 0, mx = T.S[x].size(); i < mx; i++) {
            int k = T.S[x][i];
            ls = k;
            Assign(k);
            dfs(k, x);
            for (int j = 0; j <= T.len[k] + 1; j++) {
                if (lim[x] == j)
                    S[k].ins(lim[x]), S[k].ins(f[x][j]), f[x][lim[x]++] = zero[x];
                S[k].ins(f[x][j]);
                f[x][j] = giv(x, Mul(gv(x, j), (j ? gv(k, j - 1) : 1)));
            }
            if (T.len[x] <= T.len[k] + 1)
                continue;
            int w = gv(k, T.len[k]);
            if (!w)
                S[k].ins(lim[x]), S[k].ins(zero[x]), lim[x] = T.len[k] + 1, zero[x] = giv(x, 0);
            else {
                S[k].ins(mul[x]);
                S[k].ins(imul[x]);
                S[k].ins(add[x]);
                mul[x] = Mul(mul[x], w);
                add[x] = Mul(add[x], w);
                imul[x] = Mul(imul[x], T.inv[k]);
                for (int j = 0; j <= T.len[k] + 1; j++)
                    S[k].ins(f[x][j]), f[x][j] = giv(x, Mul(gv(x, j), T.inv[k]));
            }
        }
        S[ls].ins(add[x]);
    End:
        add[x] = Add(add[x], 1);
    }
    inline void solve() {
        Assign(1);
        dfs(1, 0);
    }
} F;

struct ggg {
    int mul[N], imul[N], zero[N], add[N], lim[N], u[N];
    //	inline int GV(CI x,CI p) {return XSum(1LL*Mul[x]*(p<Lim[x]?g[x][p]:Zero[x])%X,Add[x]);}//与之前类似
    inline int gv(int x, int p) { return Add(Mul(mul[x], (p < lim[x] ? g[x][p] : zero[x])), add[x]); }
    inline int giv(int x, int v) { return Mul(imul[x], Add(v, -add[x])); }
    inline void dfs(int x, int fa) {
        //		for(int i=0;i<=T.len[x];i++) printf("g[%d][%d]=%d\n",x,i,g[x][i]);
        u[0] = 1;
        reverse(T.S[x].begin(), T.S[x].end());
        ans = Add(ans, fpow(Mul(Add(F.gv(x, L), -1), gv(x, L)), K));
        if (fa)
            ans = Add(ans, -fpow(Mul(Add(F.gv(x, L - 1), -1), Add(gv(x, L), -1)), K));
        if (!T.s[x])
            return;
        int prod = 1, Mx = 0;
        for (int i = 0, mx = T.S[x].size(); i < mx; i++) {
            int k = T.S[x][i];
            S[k].reset();
            lim[k] = L + 1;
            mul[k] = imul[k] = 1;
            for (int j = max(L - T.len[k], 0); j <= L; j++) {
                g[k][j] = Add(Mul((j ? gv(x, j - 1) : 0),
                                  (j > 1 ? Mul(F.gv(x, j - 1), (j - 2 > Mx ? prod : u[j - 2])) : 1)),
                              1);
            }
            for (int j = 0; j <= T.len[k]; j++) u[j] = Mul((j > Mx ? prod : u[j]), F.gv(k, j));
            prod = Mul(prod, F.gv(k, Mx = T.len[k]));
        }
        int ls = T.s[x];
        g[T.s[x]] = g[x] - 1;
        mul[T.s[x]] = mul[x];
        imul[T.s[x]] = imul[x];
        add[T.s[x]] = add[x];
        zero[T.s[x]] = zero[x];
        lim[T.s[x]] = lim[x] + 1;
        if (L <= T.len[T.s[x]])
            g[T.s[x]][0] = giv(T.s[x], 0);
        for (int i = 0, mx = T.S[x].size(); i < mx; i++) {
            int k = T.S[x][i];
            for (int j = max(0, L - T.len[ls]); j <= min(L, T.len[k] + 2); j++) {
                if (lim[ls] == j)
                    g[ls][lim[ls]++] = zero[ls];
                g[ls][j] = giv(ls, Mul(gv(ls, j), (j > 1 ? F.gv(k, j - 2) : 1)));
            }
            if (L <= T.len[k] + 2)
                continue;
            int w = F.gv(k, T.len[k]);
            if (!w)
                lim[ls] = T.len[k] + 2, zero[ls] = giv(ls, 0);
            else {
                mul[ls] = Mul(mul[ls], w);
                add[ls] = Mul(add[ls], w);
                imul[ls] = Mul(imul[ls], T.inv[k]);
                for (int j = max(0, L - T.len[ls]); j <= min(L, T.len[k] + 2); j++) {
                    g[ls][j] = giv(ls, Mul(gv(ls, j), T.inv[k]));
                }
            }
        }
        add[T.s[x]] = Add(add[T.s[x]], 1);
        dfs(T.s[x], x);
        for (int i = 0, mx = T.S[x].size(); i < mx; i++) {
            int k = T.S[x][i];
            if (k != fa)
                dfs(k, x);
        }
    }
    inline void solve() {
        mul[1] = add[1] = imul[1] = 1;
        lim[1] = L + 1;
        dfs(1, 0);
    }

} G;

signed main() {
    //	freopen(".in","r",stdin);
    //  freopen(".out","w",stdout);
    n = read();
    L = read();
    K = read();
    for (int i = 1; i ^ n; i++) {
        int x = read(), y = read();
        add(x, y);
        add(y, x);
    }
    T.init();
    F.solve();
    G.solve();
    printf("%d\n", ans);
    return 0;
}

「十二省联考 2019」希望

标签:splay   就是   连通块   tor   %x   problem   答案   span   void   

原文地址:https://www.cnblogs.com/fexuile/p/13027067.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!