# 题目传送门

-------------------------------------- 过年在家无聊补一下这周做的几道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 i = tot ++;
memset(son[i], -1, sizeof(son[i]));
cnt[i] = 0;
return i;
}
void init() {
tot = 0;
}
void insert(char* s) {
int p = root;
for (int i = 0; s[i]; i++) {
int index = s[i] - 'a';
if (son[p][index] == -1)
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\n", ac.slove(s));
return 0;
}

posted @ 2020-01-25 19:23  Angel_Demon  阅读(...)  评论(...编辑  收藏