#include <bits/stdc++.h>
#define N 500010
using namespace std;
// typedef long long ll;
inline int read() {
int x = 0, f = 1;
char c = getchar();
while (c < '0' || c > '9') {
if (c == '-')
f = -1;
c = getchar();
}
while (c >= '0' && c <= '9')
x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
return x * f;
}
queue<int> q;
struct Aho_Corasick_Automaton {
int c[N][26], val[N], fail[N], cnt;
void ins(char* s) { //初始化建树
int len = strlen(s);
int now = 0;
for (int i = 0; i < len; i++) {
int v = s[i] - 'a';
if (!c[now][v])
c[now][v] = ++cnt;
now = c[now][v];
}
val[now]++; //以这个节点结尾的字符串有几个
}
void build() { //建立fail数组
for (int i = 0; i < 26; i++)
if (c[0][i]) { //如果结点存在
fail[c[0][i]] = 0; // 0就是指向根结点
q.push(c[0][i]); //把结点标号放入队列
}
while (!q.empty()) {
int u = q.front();
q.pop();
for (int i = 0; i < 26; i++) //遍历结点的下一层
if (c[u][i]) {
fail[c[u][i]] = c[fail[u]][i];
q.push(c[u][i]);
//如果有这个子节点为字母i+'a',则
//让这个节点的失败指针指向(((他父亲节点)的失败指针所指向的那个节点)的下一个节点)
} else
//否则就让当前节点的这个子节点
//指向当前节点fail指针的这个子节点
c[u][i] = c[fail[u]][i];
}
}
int query(char* s) { //查询
int len = strlen(s);
int now = 0, ans = 0;
for (int i = 0; i < len; i++) {
now = c[now][s[i] - 'a'];
for (int t = now; t && ~val[t]; t = fail[t])
ans += val[t], val[t] = -1;
}
return ans;
}
} AC;
int n;
char p[1000005];
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%s", p), AC.ins(p);
AC.build();
scanf("%s", p);
int ans = AC.query(p);
printf("%d\n", ans);
return 0;
}
洛谷P3808 【模板】AC自动机(简单版)
最新推荐文章于 2024-11-08 23:39:16 发布