文章

B.哈希树

B.哈希树

题目描述

时隔两年,小 H 又一次在某场比赛中写了树哈希,他写出了以下的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
const int N = 1e6 + 10, B = 233, mod = 998244353; 

int hs[N], sz[N];
// hs[x] 表示节点 x 的 hash 值; sz[x] 表示 x 的子树节点总数

vector<int> tu[N];
// tu[x] 表示 x 的子节点

long long qpow(long long x, int y) {
    long long ans = 1;
    while (y) {
        if (y & 1) ans = ans * x % mod;
        x = x * x % mod;
        y >>= 1; 
    }
    return ans;
}

void dfs(int x) {
    hs[x] = sz[x] = 1;
    vector<pair<int, int>> V;
    for (int p : tu[x]) {
        dfs(p);
        V.push_back({sz[p], hs[p]});
        sz[x] += sz[p];
    }
    sort(V.begin(), V.end());
    // 按照子树大小排序
    for (auto now : V) {
        hs[x] = (hs[x] + qpow(B, now.first) % mod * now.second) % mod;
    }
}

事后,小 H 发现他的树哈希非常有意思,于是想要研究它的性质。 如果一棵有根树,每个节点的父亲节点编号都比这个节点大,那么小 H 就会非常喜欢它。 小 H 想知道,对于所有的 $n$ 个节点的“好树”,它们根节点的哈希值的和是多少?


输入格式

  • 第一行一个整数 $T$,表示数据组数。
  • 下面接着 $T$ 行,每行一个整数 $n$,表示树的节点数。

输出格式

  • 输出 $T$ 行,每行一个整数,表示该组数据的答案。输出对 998244353 取模。

样例

样例输入

1
2
3
4
3
4
2
5

样例输出

1
2
3
76223160
234
164636081

题目说明

存在两棵 A, B 均为 $n$ 个节点的好树,当存在某个节点,在 A 和 B 两棵树中的父节点不同时,则 A 和 B 为不同树。

本文由作者按照 CC BY 4.0 进行授权