AC 自动机
简介 #
AC
自动机不是能自动 AC
的机器,而是一种著名的多模式串匹配算法.
问题 #
给定 $n$ 个模式串 $A_1\sim A_n$ 和一个长为 $m$ 的主串 $S$,问有多少个模式串在 $S$ 中出现过.
假设 $n$ 个模式串互不相同,且字符串中仅含小写字母.可以考虑枚举 $S$ 的所有子串并进行判断.
int n, ans;
string A[], S;
int m = S.size();
for(int l = 0; l < m; l ++) {
for(int r = l + 1; r < m; r ++) {
string substr = S.substr(l, r - l + 1); // substr = S[l...r]
for(int i = 1; i <= n; i ++) {
if(substr == A[i]) {
ans ++;
}
}
}
}
cout << ans;
暴力算法($\textcolor{red}{×}$) | AC 自动机($\textcolor{green}{√}$) |
---|---|
$O(n^3)$ | $O(n+m)$ |
原理 #
Under Construction ...
模板 #
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];
}
}
void insert(char *s) {
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'];
}
e[u]++;
}
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 && e[j] != -1; j = fail[j])
res += e[j], e[j] = -1;
}
return res;
}