20250805

T1

图的计数

考虑 \(dp_{i, j}\) 表示凑了 \(i\),最后一个用的 \(j\) 的方案数。根号分治,\(j\) 只跑到根号。剩下的画图,发现把剩下的扣掉根号之后换个方向看就又变成刚才求的东西了。于是就做完了。

代码
#include <iostream>
#include <string.h>
#define int long long
using namespace std;
const int P = 999999599;
const int B = 500;
int qpow(int x, int y = P - 2) {
    int ret = 1;
    while (y) {
        if (y & 1) 
            ret = ret * x % P;
        y >>= 1;
        x = x * x % P;
    }
    return ret;
}
int n, m, X;
int f[505][505];
int v1[200005], v2[200005];
signed main() {
    freopen("graph.in", "r", stdin);
    freopen("graph.out", "w", stdout);
    cin >> n >> m;
    X = max(n / B, B) + 1;
    for (int i = 0; i <= X; i++) {
        f[0][i] = 1, v1[0] = 1;
        if (i * B <= n) 
            v2[n - i * B]++;
    }
    for (int i = 1; i <= n; i++) {
        int c = i % X;
        memset(f[c], 0, sizeof f[c]);
        for (int j = 1; j <= min(max(n / B, B - 1), i); j++) f[c][j] = f[(i - j % X + X) % X][j];
        for (int j = 1; j < max(n / B + 1, B); j++) f[c][j] = (f[c][j] + f[c][j - 1]) % (P - 1);
        for (int j = 0; j <= X; j++) {
            if (i + j * B <= n) 
                v2[n - (i + j * B)] = (v2[n - (i + j * B)] + f[c][j]) % (P - 1);
        }
        v1[i] = f[c][B - 1];
    }
    int ans = 0;
    for (int i = 0; i <= n; i++) ans += (1ll * v1[i]) * v2[i] % (P - 1);
    cout << qpow(m, ans % (P - 1)) << "\n";
    return 0;
}

T2

祖先

把贡献拆开,变成自己和子树,轻子树和重子树,轻子树之间。重剖,每次修改跳重链更新链顶父亲的信息。若修改在子树中,这样就 ok。若子树加在祖先,考虑把这些操作叠一块做,总的效果相当于自己子树加 \(x\)。拆贡献,发现只需要维护每个轻子树点贡献次数之和、轻子树互相贡献的对(pair)数、轻子树点权和即可实现更新答案。另外还需要各轻子树自己的点权和。这都是好维护的。

代码
#include <iostream>
#define int long long
#define lowbit(x) ((x) & (-(x)))
using namespace std;
int n, q;
struct BIT {
    unsigned int bit[200005];
    void add(int x, unsigned int y) { for (; x <= n; x += lowbit(x)) bit[x] += y; }
    unsigned int query(int x) {
        unsigned int ret = 0;
        for (; x; x -= lowbit(x)) ret += bit[x];
        return ret;
    }
} bit;
unsigned int a[200005];
int head[200005], nxt[200005], to[200005], ecnt;
void add(int u, int v) { to[++ecnt] = v, nxt[ecnt] = head[u], head[u] = ecnt; }
int _dfn[200005], top[200005], dfn[200005], f[200005], ncnt;
int *L = dfn, R[200005];
int son[200005];
unsigned int sz[200005];
unsigned int sh[200005], sl[200005], ctl[200005], sv[200005], cnt[200005];
unsigned int val[200005];
struct Segment_Tree {
    unsigned int s[800005], tg[800005], len[800005];
    void tag(int o, unsigned int v) { s[o] += v * len[o], tg[o] += v; }
    void pushdown(int o) {
        if (!tg[o]) 
            return;
        tag(o << 1, tg[o]);
        tag(o << 1 | 1, tg[o]);
        tg[o] = 0;
    }
    void Build(int o, int l, int r) {
        len[o] = r - l + 1;
        if (l == r) {
            s[o] = a[_dfn[l]];
            return;
        }
        int mid = (l + r) >> 1;
        Build(o << 1, l, mid);
        Build(o << 1 | 1, mid + 1, r);
        s[o] = s[o << 1] + s[o << 1 | 1];
    }
    void Add(int o, int l, int r, int L, int R, unsigned int v) {
        if (L <= l && r <= R) 
            return tag(o, v);
        pushdown(o);
        int mid = (l + r) >> 1;
        if (L <= mid) 
            Add(o << 1, l, mid, L, R, v);
        if (R > mid) 
            Add(o << 1 | 1, mid + 1, r, L, R, v);
        s[o] = s[o << 1] + s[o << 1 | 1];
    }
    unsigned int Query(int o, int l, int r, int L, int R) {
        if (L > R) 
            return 0;
        if (L <= l && r <= R) 
            return s[o];
        pushdown(o);
        int mid = (l + r) >> 1;
        if (R <= mid) 
            return Query(o << 1, l, mid, L, R);
        if (L > mid) 
            return Query(o << 1 | 1, mid + 1, r, L, R);
        return Query(o << 1, l, mid, L, R) + Query(o << 1 | 1, mid + 1, r, L, R);
    }
} seg;
void dfs1(int x) {
    sz[x] = 1;
    sv[x] = a[x];
    for (int i = head[x]; i; i = nxt[i]) {
        int v = to[i];
        dfs1(v);
        sv[x] += sv[v];
        sz[x] += sz[v];
        if (sz[v] > sz[son[x]]) 
            son[x] = v;
    }
    unsigned int c = 0;
    for (int i = head[x]; i; i = nxt[i]) {
        int v = to[i];
        if (v != son[x]) {
            val[x] += sv[v] * (sz[x] - sz[son[x]] - sz[v] - 1);
            cnt[x] += sz[v] * c;
            c += sz[v];
        }
    }
}
void dfs2(int x, int t) {
    _dfn[dfn[x] = ++ncnt] = x;
    top[x] = t;
    if (son[x]) 
        dfs2(son[x], t);
    sh[x] = sv[son[x]];
    for (int i = head[x]; i; i = nxt[i]) {
        int v = to[i];
        if (v != son[x]) {
            dfs2(v, v);
            ctl[x] += sv[v] * sl[x];
            sl[x] += sv[v];
        }
    }
    R[x] = ncnt;
}
void Change(int x, unsigned int y) {
    while (f[top[x]]) {
        x = top[x];
        ctl[f[x]] += (sl[f[x]] - sv[x]) * y;
        sl[f[x]] += y;
        val[f[x]] += y * (sz[f[x]] - sz[x] - sz[son[f[x]]] - 1);
        sv[x] += y;
        x = f[x];
    }
}
unsigned int Query(int x) {
    unsigned int vx = seg.Query(1, 1, n, dfn[x], dfn[x]), tg = bit.query(dfn[x]);
    unsigned int sumh = 0, suml = 0;
    if (son[x]) 
        sumh = seg.Query(1, 1, n, L[son[x]], R[son[x]]), suml = seg.Query(1, 1, n, R[son[x]] + 1, R[x]);
    unsigned int v1 = vx * (sumh + suml);
    unsigned int v2 = sumh * suml;
    unsigned int v3 = ctl[x] + tg * val[x] + tg * tg * cnt[x];
    return v1 + v2 + v3;
}
signed main() {
    freopen("ancestor.in", "r", stdin);
    freopen("ancestor.out", "w", stdout);
    cin >> n >> q;
    for (int i = 2; i <= n; i++) cin >> f[i], add(f[i], i);
    for (int i = 1; i <= n; i++) cin >> a[i];
    dfs1(1);
    dfs2(1, 1);
    seg.Build(1, 1, n);
    while (q--) {
        char op;
        int x;
        unsigned int y;
        cin >> op >> x;
        if (op == 'S') {
            cin >> y;
            seg.Add(1, 1, n, dfn[x], dfn[x], y);
            Change(x, y);
        } else if (op == 'M') {
            cin >> y;
            Change(x, y * sz[x]);
            bit.add(L[x], y);
            bit.add(R[x] + 1, -y);
            seg.Add(1, 1, n, L[x], R[x], y);
        } else 
            cout << Query(x) % (1ull << 63) << "\n";
    }
    return 0;
}

T3

大哭

首先若序列确定,我们一定按做菜时间从慢到快做。因此按这个顺序 dp。接下来的 dp 没完全懂。大概就是首先你考虑若两个 \(a_i\) 构成逆序对,那一定不会选后面的扔掉前面的,因为这样不优。因此必然存在一条左下到右上的折线满足其上方的点都被扔掉,下方的都被保留。我们先考虑枚举答案,求出有多少序列的答案比这个大。由于对于每个序列来说,不合法的时间数量就是其最短时间,因此求出这个东西之后答案是容易算的。那么接下来考虑对着折线 dp。我们需要让每一个 \(a\) 序列唯一对应一条折线。显然的考虑是让折线尽可能靠下,也就是卡着保留的东西。然后折线上同一横之间的元素我们钦定前面的被扔掉,后面的保留。然后考虑我们扔掉一些东西,肯定是因为留下它们会爆掉当前枚举的答案。也就是我们在每个位置检查,若这个位置的前缀和加当前 \(b_i\) 加当前折线位置爆了,那么说明我们这一段扔掉的东西是合理的,接下来可以选择把折线往上移,或者留在原位置(如果当前这一横着的段没有保留过东西)。那么最后我们希望所有折线扔掉的东西都被验证合理,于是让所有折线最后都走到 \(m + 1\) 高度。于是有 dp:\(f_{i, j, k, l, 0 / 1/ 2}\) 表示考虑了前 \(i\) 个,保留的东西的和为 \(j\),保留了 \(k\) 个东西,当前折线在 \(l\),(没见过 \(l\),见过 \(l\) 且都扔了,见过 \(l\) 且扔了且后面留了一段后缀),的方案数。转移枚举新填个啥即可。容易用前缀和优化。

代码
#include <iostream>
#include <algorithm>
#include <string.h>
#include <vector>
using namespace std;
const int P = 998244353, N = 700;
inline void Madd(int &x, int y) { (x += y) >= P ? (x -= P) : 0; }
int n, m;
int b[505];
int f[35][705][35][25][3];
// at i, presum j, choose k, line pos l
int g[705][35][25][3];
int ans[35], mxb;
signed main() {
    freopen("dk.in", "r", stdin);
    freopen("dk.out", "w", stdout);
    cin >> n >> m;
    for (int i = 1; i <= n; i++) cin >> b[i], mxb = max(mxb, b[i]);
    sort(b + 1, b + n + 1, greater<int>());
    for (int j = 0; j <= N; j++) for (int i = 1; i <= m + 1; i++) f[0][j][0][i][0] = 1;
    for (int i = 1; i <= n; i++) {
        for (int j = 0; j <= N; j++) for (int k = 0; k <= i; k++) for (int l = 1; l <= m + 1; l++) f[i][j][k][l][0] = f[i][j][k][l][1] = f[i][j][k][l][2] = 0;
        memset(g, 0, sizeof g);
        for (int j = 0; j <= N; j++) {
            for (int k = 0; k < i; k++) {
                for (int l = 1; l <= m + 1; l++) {
                    // choose < l
                    Madd(g[max(0, j - l + 1)][k + 1][l][0], f[i - 1][j][k][l][0]);
                    Madd(g[max(0, j - l + 1)][k + 1][l][1], f[i - 1][j][k][l][1]);
                    Madd(g[max(0, j - l + 1)][k + 1][l][2], f[i - 1][j][k][l][2]);
                    Madd(g[j][k + 1][l][0], P - f[i - 1][j][k][l][0]);
                    Madd(g[j][k + 1][l][1], P - f[i - 1][j][k][l][1]);
                    Madd(g[j][k + 1][l][2], P - f[i - 1][j][k][l][2]);
                    // choose = l
                    if (l != m + 1) {
                        Madd(f[i][j][k][l][1], f[i - 1][j][k][l][0]);
                        Madd(f[i][j][k][l][1], f[i - 1][j][k][l][1]);
                        if (l <= j) {
                            Madd(f[i][j - l][k + 1][l][2], f[i - 1][j][k][l][1]);
                            Madd(f[i][j - l][k + 1][l][2], f[i - 1][j][k][l][2]);
                        }
                    }
                    // choose > l
                    if (l != m + 1) {
                        Madd(f[i][j][k][l][0], 1ll * f[i - 1][j][k][l][0] * (m - l) % P);
                        Madd(f[i][j][k][l][1], 1ll * f[i - 1][j][k][l][1] * (m - l) % P);
                        Madd(f[i][j][k][l][2], 1ll * f[i - 1][j][k][l][2] * (m - l) % P);
                    }
                }
            }
        }
        for (int j = 0; j <= N; j++) for (int k = 0; k <= i; k++) for (int l = 1; l <= m + 1; l++) {
            if (j) {
                Madd(g[j][k][l][0], g[j - 1][k][l][0]);
                Madd(g[j][k][l][1], g[j - 1][k][l][1]);
                Madd(g[j][k][l][2], g[j - 1][k][l][2]);
            }
            Madd(f[i][j][k][l][0], g[j][k][l][0]);
            Madd(f[i][j][k][l][1], g[j][k][l][1]);
            Madd(f[i][j][k][l][2], g[j][k][l][2]);
        }
        memset(g, 0, sizeof g);
        for (int j = 0; j <= N; j++) {
            for (int k = 0; k <= i; k++) {
                for (int l = 1; l <= m + 1; l++) {
                    if (b[i] > j) 
                        f[i][j][k][l][0] = f[i][j][k][l][1] = f[i][j][k][l][2] = 0;
                    else if (b[i] + l > j) {
                        Madd(g[j][k][l][0], f[i][j][k][l][1]);
                        Madd(g[j][k][l + 1][0], f[i][j][k][l][2]);
                        f[i][j][k][l][1] = f[i][j][k][l][2] = 0;
                    }
                }
            }
        }
        for (int j = 0; j <= N; j++) for (int k = 0; k <= i; k++) for (int l = 1; l <= m + 1; l++) Madd(g[j][k][l][0], g[j][k][l - 1][0]), Madd(f[i][j][k][l][0], g[j][k][l][0]);
    }
    for (int j = 0; j <= N; j++) {
        for (int k = n; k; k--) {
            Madd(f[n][j][k][m + 1][0], f[n][j][k + 1][m + 1][0]);
            Madd(ans[k], f[n][j][k][m + 1][0]);
        }
    }
    long long pw = 1;
    for (int i = 1; i <= n; i++) pw = pw * m % P;
    for (int i = 1; i <= n; i++) cout << ((N + 1) * pw + P - ans[i]) % P << " ";
    cout << "\n";
    return 0;
}

T4

第一问答案为奇度点个数除以二上取整。接下来考虑第二问。

先二分答案,设 \(f_i\) 表示子树链最少且合法情况下最短向父亲延伸长度为多少的链。若当前点儿子有奇数个,那么一定要延伸上去一条,枚举延伸哪条上去,把剩下的大配小,检查合法性即可。接下来若当前点有偶数个儿子,那么先检查子树两两配对,若不能则我们一定扔掉最长的儿子,剩下的做奇数情况即可。

接下来考虑第三问。我们设 \(f_{i, j}\) 表示 \(i\) 子树向上延伸 \(j\) 长度的方案数。然后还是考虑当前点儿子数奇偶性。若有奇数个儿子,还是枚举哪条延伸上去,接下来只需要求剩下的儿子两两配对,链长不超过第二问答案的合法方案数。可以先求出 \(c_{i, j}\) 表示 \(i\)\(j\) 儿子这样配对的方案数,然后只需要一个状压 dp 即可。每次把当前状态的 lowbit 拿出来找匹配,这样做的话这个状压 dp 的合法状态数就会很少。\(c_{i, j}\) 可以枚举一个儿子,然后在另一个儿子的 dp 数组上前缀和一下。然后考虑偶数。先算子树两两万门匹配的方案数,然后若当前点不为根,考虑枚举一个儿子向上延伸。再枚举扔掉的儿子,则方案数也是容易计算的。这样就是 \(n^2\) 的。发现状态和深度有关,考虑长剖。转移时特殊考虑长儿子,只需要拿数据结构维护区间乘单点加区间求和即可。实现上可以考虑对着 dfn 开线段树,dp 数组地址按 dfn 分配。总复杂度 \(\mathcal{O}(能过)\)

代码
#include <iostream>
#include <algorithm>
#include <string.h>
#include <vector>
using namespace std;
const int P = 998244353;
inline void Madd(int &x, int y) { (x += y) >= P ? (x -= P) : 0; }
inline int Msum(int x, int y) { return Madd(x, y), x; }
#define getchar() p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++
char buf[1<<21], *p1, *p2, ch;
long long read() {
    long long ret = 0, neg = 0; char c = getchar(); neg = (c == '-');
    while (c < '0' || c > '9') c = getchar(), neg |= (c == '-');
    while (c >= '0' && c <= '9') ret = ret * 10 + c - '0', c = getchar();
    return ret * (neg ? -1 : 1);
}
int n, type, cod, ans2;
int deg[100005], f[100005];
vector<int> G[100005];
namespace Type_2 {
    int mid, ok;
    void dfs0(int x, int fa) {
        f[x] = fa;
        if (x != 1) 
            G[x].erase(find(G[x].begin(), G[x].end(), fa));
        for (auto v : G[x]) dfs0(v, x);
    }
    int dfs(int x) {
        vector<int> g;
        for (int v : G[x]) {
            g.emplace_back(dfs(v));
            ok &= (g.back() <= mid);
        }
        sort(g.begin(), g.end());
        int scnt = G[x].size();
        if (!(scnt & 1)) {
            bool no = 0;
            for (int i = 0, j = scnt - 1; i < j; i++, j--) no |= (g[i] + g[j] > mid);
            if (!no) 
                return 1;
            if (x == 1) {
                ok = 0;
                return 0;
            }
            g.pop_back();
        }
        for (int i = 0; i < (int)g.size(); i++) {
            bool no = 0;
            for (int j = (!i), k = (int)g.size() - 1 - (i == (int)g.size() - 1); j < k; j++, j += (j == i), k--, k -= (k == i)) 
                no |= (g[j] + g[k] > mid);
            if (!no) 
                return g[i] + 1;
        }
        ok = 0;
        return 0;
    }
    int work() {
        dfs0(1, 0);
        int l = 1, r = n, ans = 0;
        while (l <= r) {
            mid = (l + r) >> 1;
            if (ok = 1, dfs(1), ok) 
                ans = mid, r = mid - 1;
            else 
                l = mid + 1;
        }
        return ans;
    }
}
namespace Type_3 {
    struct Segment_Tree {
        int s[400005], mtag[400005];
        inline void tag(int o, int v) { mtag[o] = 1ll * mtag[o] * v % P, s[o] = 1ll * s[o] * v % P; }
        inline void pushdown(int o) {
            if (mtag[o] == 1) 
                return;
            tag(o << 1, mtag[o]);
            tag(o << 1 | 1, mtag[o]);
            mtag[o] = 1;
        }
        void Build(int o, int l, int r) {
            mtag[o] = 1;
            if (l == r) 
                return;
            int mid = (l + r) >> 1;
            Build(o << 1, l, mid);
            Build(o << 1 | 1, mid + 1, r);
        }
        void Add(int o, int l, int r, int x, int y) {
            if (l == r) 
                return Madd(s[o], y);
            pushdown(o);
            int mid = (l + r) >> 1;
            if (x <= mid) 
                Add(o << 1, l, mid, x, y);
            else 
                Add(o << 1 | 1, mid + 1, r, x, y);
            s[o] = Msum(s[o << 1], s[o << 1 | 1]);
        }
        void Mul(int o, int l, int r, int L, int R, int v) {
            if (L <= l && r <= R) 
                return tag(o, v);
            pushdown(o);
            int mid = (l + r) >> 1;
            if (L <= mid) 
                Mul(o << 1, l, mid, L, R, v);
            if (R > mid) 
                Mul(o << 1 | 1, mid + 1, r, L, R, v);
            s[o] = Msum(s[o << 1], s[o << 1 | 1]);
        }
        int Query(int o, int l, int r, int L, int R) {
            if (L <= l && r <= R) 
                return s[o];
            pushdown(o);
            int mid = (l + r) >> 1;
            if (R <= mid) 
                return Query(o << 1, l, mid, L, R);
            if (L > mid) 
                return Query(o << 1 | 1, mid + 1, r, L, R);
            return Msum(Query(o << 1, l, mid, L, R), Query(o << 1 | 1, mid + 1, r, L, R));
        }
    } seg;
    vector<int> bit[70005];
    int dist[100005], son[100005], dfn[100005], ncnt;
    int vis[70005], rec[70005], val[20][20], X;
    int dp[100005];
    int dfs(int S) {
        if (vis[S] == X) 
            return rec[S];
        if (!S) 
            return 1;
        vis[S] = X, rec[S] = 0;
        for (int i = 1; i < (int)bit[S].size(); i++) {
            int a = bit[S][0], b = bit[S][i];
            Madd(rec[S], 1ll * dfs(S ^ (1 << a) ^ (1 << b)) * val[a][b] % P);
        }
        return rec[S];
    }
    void dfs1(int x) {
        for (int v : G[x]) {
            dfs1(v);
            dist[x] = max(dist[x], dist[v] + 1);
            if (dist[v] >= dist[son[x]]) 
                son[x] = v;
        }
    }
    vector<int> tmp[20];
    void dfs2(int x) {
        dfn[x] = ++ncnt;
        if (!dist[x]) {
            seg.Add(1, 1, n, dfn[x], 1);
            dp[dfn[x]] = 1;
            return;
        }
        dfs2(son[x]);
        for (int v : G[x]) v != son[x] ? dfs2(v) : void();
        int scnt = G[x].size(), S = (1 << scnt) - 1, hid = 0;
        memset(val, 0, sizeof val);
        for (int i = 0; i < scnt; i++) {
            int v = G[x][i]; tmp[i].resize(0);
            if (v == son[x]) {
                hid = i;
                continue;
            }
            tmp[i].resize(dist[v] + 2);
            for (int j = 1; j < dist[v] + 2; j++) tmp[i][j] = Msum(tmp[i][j - 1], dp[dfn[v] + j - 1]);
        }
        for (int i = 0; i < scnt; i++) {
            int v1 = G[x][i], v2;
            for (int j = i + 1; j < scnt; j++) {
                v2 = G[x][j];
                if (v1 == son[x] || v2 == son[x]) 
                    continue;
                int a, b = min(ans2 - 1, dist[v2] + 1);
                for (a = 1; a <= dist[v1] + 1; a++) {
                    b -= (a + b > ans2);
                    if (b <= 0) 
                        break;
                    Madd(val[i][j], 1ll * dp[dfn[v1] + a - 1] * tmp[j][b] % P);
                    Madd(val[j][i], 1ll * dp[dfn[v1] + a - 1] * tmp[j][b] % P);
                }
            } v2 = son[x];
            if (v1 == son[x]) 
                continue;
            int a, b = min(ans2 - 1, dist[v2] + 1);
            for (a = 1; a <= dist[v1] + 1; a++) {
                b -= (a + b > ans2);
                if (b <= 0) 
                    break;
                Madd(val[i][hid], 1ll * dp[dfn[v1] + a - 1] * seg.Query(1, 1, n, dfn[v2], dfn[v2] + b - 1) % P);
                Madd(val[hid][i], 1ll * dp[dfn[v1] + a - 1] * seg.Query(1, 1, n, dfn[v2], dfn[v2] + b - 1) % P);
            }
        }
        X = x;
        if (scnt & 1) {
            seg.Mul(1, 1, n, dfn[son[x]], dfn[x] + dist[x], dfs(S ^ (1 << hid)));
            for (int i = 0; i < scnt; i++) {
                int v = G[x][i], coe;
                if (v != son[x]) {
                    coe = dfs(S ^ (1 << i));
                    for (int j = 1; j <= dist[v] + 1; j++) seg.Add(1, 1, n, dfn[x] + j, 1ll * dp[dfn[v] + j - 1] * coe % P);
                }
            }
        } else {
            if (x != 1 || dfs(S) == 0) {
                for (int i = 0; i < scnt; i++) {
                    int v = G[x][i];
                    if (i == hid) {
                        tmp[i].resize(1);
                        tmp[i][0] = seg.Query(1, 1, n, dfn[v], dfn[v] + min(ans2, dist[v] + 1) - 1);
                    } else 
                        tmp[i][0] = tmp[i][min(ans2, dist[v] + 1)];
                }
                int s = 0;
                for (int j = 0; j < scnt; j++) {
                    if (j != hid) 
                        Madd(s, 1ll * tmp[j][0] * dfs(S ^ (1 << hid) ^ (1 << j)) % P);
                }
                seg.Mul(1, 1, n, dfn[son[x]], dfn[x] + dist[x], s);
                for (int i = 0; i < scnt; i++) {
                    int v = G[x][i];
                    if (v != son[x]) {
                        for (int j = 0; j < scnt; j++) {
                            if (i != j) {
                                for (int k = 1; k <= min(dist[v] + 1, ans2 - 1); k++) 
                                    seg.Add(1, 1, n, dfn[x] + k, 1ll * dp[dfn[v] + k - 1] * tmp[j][0] % P * dfs(S ^ (1 << i) ^ (1 << j)) % P);
                            }
                        }
                    }
                }
            } else 
                seg.Mul(1, 1, n, dfn[x] + 1, dfn[x] + dist[x], 0);
            seg.Add(1, 1, n, dfn[x], dfs(S));
        }
        if (son[f[x]] != x) {
            for (int i = 1; i <= dist[x] + 1; i++) 
                dp[dfn[x] + i - 1] = seg.Query(1, 1, n, dfn[x] + i - 1, dfn[x] + i - 1);
        }
    }
    int work() {
        for (int i = 0; i < (1 << 16); i++) {
            for (int j = 0; j < 16; j++) {
                if (i & (1 << j)) 
                    bit[i].emplace_back(j);
            }
        }
        seg.Build(1, 1, n);
        dfs1(1);
        dfs2(1);
        return seg.Query(1, 1, n, 1, min(dist[1] + 1, ans2 + 1));
    }
}
signed main() {
    freopen("tree.in", "r", stdin);
    freopen("tree.out", "w", stdout);
    n = read(), type = read();
    for (int i = 1; i < n; i++) {
        int u = read(), v = read();
        ++deg[u], ++deg[v];
        G[u].emplace_back(v);
        G[v].emplace_back(u);
    }
    for (int i = 1; i <= n; i++) cod += (deg[i] & 1);
    cout << (cod + 1) / 2 << "\n";
    if (type == 1) 
        return 0;
    ans2 = Type_2::work();
    cout << ans2 << "\n";
    if (type == 2) 
        return 0;
    cout << Type_3::work() << "\n";
    return 0;
}

根号求分拆数。

posted @ 2025-08-08 20:38  forgotmyhandle  阅读(5)  评论(0)    收藏  举报