题目传送门
-------------------------------------- 过年在家无聊补一下这周做的几道AC自动机的模板题
sol:标准AC自动机,注意不能重复跳fail边,像"aaaaaaa...aaaaaaaa"这样的数据每跳一次fail边只往上走了一层。
- AC自动机
#include <bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<int, int> PII; const int MAXN = 1e6 + 10; struct Trie { int son[MAXN][26], cnt[MAXN], fail[MAXN]; int tot, root; int add_node() { int i = tot ++; memset(son[i], -1, sizeof(son[i])); cnt[i] = 0; return i; } void init() { tot = 0; root = add_node(); } void insert(char* s) { int p = root; for (int i = 0; s[i]; i++) { int index = s[i] - 'a'; if (son[p][index] == -1) son[p][index] = add_node(); p = son[p][index]; } cnt[p] ++; } void build() { queue<int> que; fail[root] = root; for (int i = 0; i < 26; i++) { if (son[root][i] == -1) son[root][i] = root; else { fail[son[root][i]] = root; que.push(son[root][i]); } } while (!que.empty()) { int p = que.front(); que.pop(); for (int i = 0; i < 26; i++) { if (son[p][i] == -1) son[p][i] = son[fail[p]][i]; else { fail[son[p][i]] = son[fail[p]][i]; que.push(son[p][i]); } } } } int slove(char* s) { int p = root, res = 0; for (int i = 0; s[i]; i++) { int index = s[i] - 'a'; p = son[p][index]; for (int tmp = p; tmp != root && cnt[tmp] != -1; tmp = fail[tmp]) { res += cnt[tmp]; // 访问过就把cnt设置成-1,防止下次跳fail边重复进入 cnt[tmp] = -1; } } return res; } } ac; char s[MAXN]; int main() { ac.init(); int n; scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%s", s); ac.insert(s); } scanf("%s", s); ac.build(); printf("%d ", ac.slove(s)); return 0; }