自动AC机是什么?交上去就能AC?
要真是这样,那还要OI干什么。
AC自动机相当于是Trie上KMP,相对于KMP,解决多串匹配问题,但比KMP要简单,核心思想就是两句话。
Code
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
const int maxn = 1e6 + 7;
using namespace std;
char s[maxn];
queue <int> q;
struct Aho_Corasick_Automaton
{
int ch[maxn][26];
int val[maxn];
int fail[maxn];
int cnt;
inline void insert(char *s)
{
int u = 0, len = strlen(s);
for (int i = 0; i < len; i++) {
int c = s[i] - 'a';
if (!ch[u][c]) ch[u][c] = ++cnt;
u = ch[u][c];
}
val[u]++;
} //插入和Trie一毛一样
inline void build()
{
for (int i = 0; i < 26; i++) if (ch[0][i]) fail[ch[0][i]] = 0, q.push(ch[0][i]);
while (!q.empty()) { //对整颗Trie进行Bfs,求出每个节点的Fail指针
int u = q.front();
q.pop();
for (int i = 0; i < 26; i++)
if (ch[u][i]) fail[ch[u][i]] = ch[fail[u]][i], q.push(ch[u][i]); //这句话是AC自动机的核心思想,自己手造一个AC自动机的图就可以理解
else ch[u][i] = ch[fail[u]][i]; //这句话是为了给上一句话和下面的查询提供便利(这个便利是必要的)
}
}
inline int query(char *s)
{
int u = 0, ans = 0, len = strlen(s);
for (int i = 0; i < len; i++) {
u = ch[u][s[i] - 'a'];
for (int j = u; j && ~val[j]; j = fail[j]) ans += val[j], val[j] = -1; //把val标为-1就可以保证Trie中每个点至多被访问一遍,保证了复杂度
}
return ans;
}
} ac;
int main(void)
{
int n;
cin >> n;
while (n--) {
scanf("%s", s);
ac.insert(s);
}
ac.build();
scanf("%s", s);
cout << ac.query(s);
return 0;
}
忍不住吐槽一下,为什么洛谷里好多(因为懒得再往后看了)AC自动机加强版题解代码都没我自己yy的强?每个点都跳一路的Fail?估计是欺负数据太弱了。把Trie的大小开到1e6这些题解就都过不了了。知不知道什么叫树形dp
(上面的板子是简单版的)