AC自动机
Tags:字符串
作业部落
一、概述
\(Aho-Corasic\ automaton\),中文名\(AC\)自动机,是\(Trie\)图的一种,实现高效多串匹配单串的一种字符串算法
跟踪dalao的blog
\(Trie\)树上令一个点表示从根到它的串,那么一个点的fail
指向和它拥有最长后缀的串(所以可以指向\(0\))
二、题单
- [x] [luogu3808]【模板】AC自动机(简单版) https://www.luogu.org/problemnew/show/P3808
- [x] [luogu3796]【模板】AC自动机(加强版)https://www.luogu.org/problemnew/show/P3796
- [ ] [CJOJ1435] 【模板题 USACO】AC自动机 https://oj.changjun.com.cn/problem/detail/pid/1435
- [x] [HDU2296]Ring https://vjudge.net/problem/HDU-2296#author=prayerhgq
- [x] [BZOJ1030][JSOI2007]文本生成器 https://www.luogu.org/problemnew/show/P4052
- [x] [BZOJ3172][TJOI2013]单词 https://www.luogu.org/problemnew/show/P3966
- [x] [Luogu2444][POI2000]病毒 https://www.luogu.org/problemnew/show/P2444
- [x] [BZOJ1009][HNOI2008]GT考试 https://www.luogu.org/problemnew/show/P3193
- [x] [BZOJ3530][SDOI2014]数数 https://www.luogu.org/problemnew/show/P3311
- [x] [Luogu3121][USACO15FEB]审查Censoring https://www.luogu.org/problemnew/show/P3121
- [x] [BZOJ1212][HNOI2004]L语言 https://www.luogu.org/problemnew/show/P2292
- [x] [Luogu3041][USACO12JAN]视频游戏的连击Video Game Combos https://www.luogu.org/problemnew/show/P3041
- [ ] [BZOJ2434]阿狸的打字机 https://www.luogu.org/problemnew/show/P2414
[ ] [BZOJ2754]喵星球上的点名 https://www.luogu.org/problemnew/show/P2336
三、做题经验
1
用来多串匹配单串或多串,效率高于\(KMP\)(可以代替),但是字符集很大时候需要大空间或用时间换空间(开\(set\))
2
套路:\(dp[i][j]\)表示到第\(i\)号节点(长串匹配到\(i\)),匹配长度为\(j\)(短串匹配到\(j\))的方案数啥的四、Tip
!
\(Fail\)是一棵树,但是\(AC\)自动机是\(Trie\)图,可以存在环(病毒)
!
构造数据的时候,可以检查自己写的\(AC\)自动机是否可以从第一位开始匹配五、模板
洛谷3808模板1
首先建出\(Trie\)树(\(Build\)),然后通过\(BFS\)算出\(Fail\),再进行匹配#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<queue> using namespace std; const int MAXN=1000100; struct Node{int ch[26],fail,end;}t[MAXN]; char s[MAXN]; int N,node; queue<int> Q; void Build() { int len=strlen(s),x=0; for(int i=0;i<len;i++) { if(!t[x].ch[s[i]-'a']) t[x].ch[s[i]-'a']=++node; x=t[x].ch[s[i]-'a']; } t[x].end++; } void Get_Fail() { for(int i=0;i<26;i++) if(t[0].ch[i]) Q.push(t[0].ch[i]); while(!Q.empty()) { int x=Q.front();Q.pop(); for(int i=0;i<26;i++) if(t[x].ch[i]) { t[t[x].ch[i]].fail=t[t[x].fail].ch[i]; Q.push(t[x].ch[i]); } else t[x].ch[i]=t[t[x].fail].ch[i]; } } int AC() { int len=strlen(s),x=0,ans=0; for(int i=0;i<len;i++) { x=t[x].ch[s[i]-'a']; for(int p=x;p&&~t[p].end;p=t[p].fail) ans+=t[p].end,t[p].end=-1; } return ans; } int main() { cin>>N;while(N--){scanf("%s",s);Build();} Get_Fail();scanf("%s",s); printf("%d\n",AC());return 0; }