# AC自动机(Trie图优化)

Writer: kesisour(周宸宇)

# 说明

题目:Luogu P3796

注释掉的是本题的查询功能,其余为基础自动机,取消注释可直接过题

# 使用

AC::init() 初始化操作

AC::insert(char *s, int id) 待匹配字符串的地址与编号

AC::build() 建立自动机

# Tips

1. 字符串在输入的时候将首地址空出来,类似scanf("%s", t + 1)

2. 模板采用Trie图优化,失配时不用暴力跳fail,tr[u][i] = tr[fail[u]][i]

# 代码

const int N = 156, L = 1e6 + 6;

namespace AC {
    const int SZ = N * 80;
    int tot, tr[SZ][26];
    int fail[SZ], idx[SZ], val[SZ];
    // int cnt[N];  // 记录第 i 个字符串的出现次数
    void init() {
        memset(fail, 0, sizeof(fail));
        memset(tr, 0, sizeof(tr));
        memset(val, 0, sizeof(val));
        // memset(cnt, 0, sizeof(cnt));
        memset(idx, 0, sizeof(idx));
        tot = 0;
    }

    void insert(char *s, int id) {  // id 表示原始字符串的编号
        int u = 0;
        for (int i = 1; s[i]; i++) {
            if (!tr[u][s[i] - 'a']) tr[u][s[i] - 'a'] = ++tot;
            u = tr[u][s[i] - 'a'];
        }
        idx[u] = id;
    }

    queue<int> q;

    void build() {
        for (int i = 0; i < 26; i++)
            if (tr[0][i]) q.push(tr[0][i]);
        while (q.size()) {
            int u = q.front();
            q.pop();
            for (int i = 0; i < 26; i++) {
                if (tr[u][i])
                    fail[tr[u][i]] = tr[fail[u]][i], q.push(tr[u][i]);
                else
                    tr[u][i] = tr[fail[u]][i];
            }
        }
    }

    // int query(char *t) {  // 返回最大的出现次数
    //     int u = 0, res = 0;
    //     for (int i = 1; t[i]; i++) {
    //         u = tr[u][t[i] - 'a'];
    //         for (int j = u; j; j = fail[j]) val[j]++;
    //     }
    //     for (int i = 0; i <= tot; i++)
    //         if (idx[i]) res = max(res, val[i]), cnt[idx[i]] = val[i];
    //     return res;
    // }

}  // namespace AC


// int n;
// char s[N][100], t[L];

// int main() {
//     while (~scanf("%d", &n)) {
//         if (n == 0) break;
//         AC::init();
//         for (int i = 1; i <= n; i++) scanf("%s", s[i] + 1), AC::insert(s[i], i);
//         AC::build();
//         scanf("%s", t + 1);
//         int x = AC::query(t);
//         printf("%d\n", x);
//         for (int i = 1; i <= n; i++)
//             if (AC::cnt[i] == x) printf("%s\n", s[i] + 1);
//     }
//     return 0;
// }

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74