最近正在学AC自动机,按照惯例需要刷一套kuangbin的AC自动机专题巩固
在网上看过很多模板,感觉kuangbin大神的模板最为简洁,于是就选择了用kuangbin大神的模板。
AC自动机其实就是字典树和KMP的结合,然后去思考一下KMP的原理,然后就是在字典树上实现KMP
这里最重要的思想可能就是fail的思想,就像KMP一样,匹配失败后,有一个next的数组去回溯(最长公共前缀后缀)
如何理解了KMP的话,感觉这个不会很难理解,字典树是一个非常简单的东西就不用讲了吧。
HDU - 2222,HDU - 2896,HDU - 3065,ZOJ - 3430
这是我总结出来的AC自动机解决的第一类问题,求文本串和模式串的关系(模式串出现几次之类的问题)
我把这几题放一起写了算了,因为套路一样随便改一下就好了
Keywords Search HDU - 2222
询问有多少个模式串出现在了文本串里面。
将模式串插入Trie树中,然后直接查询就好了。
1 #include <set> 2 #include <map> 3 #include <stack> 4 #include <queue> 5 #include <cmath> 6 #include <cstdio> 7 #include <string> 8 #include <vector> 9 #include <time.h> 10 #include <cstring> 11 #include <iostream> 12 #include <algorithm> 13 #include <unordered_map> 14 15 #define pi acos(-1.0) 16 #define eps 1e-9 17 #define fi first 18 #define se second 19 #define rtl rt<<1 20 #define rtr rt<<1|1 21 #define bug printf("******\n") 22 #define mem(a, b) memset(a,b,sizeof(a)) 23 #define name2str(x) #x 24 #define fuck(x) cout<<#x" = "<<x<<endl 25 #define sf(n) scanf("%d", &n) 26 #define sff(a, b) scanf("%d %d", &a, &b) 27 #define sfff(a, b, c) scanf("%d %d %d", &a, &b, &c) 28 #define sffff(a, b, c, d) scanf("%d %d %d %d", &a, &b, &c, &d) 29 #define pf printf 30 #define FIN freopen("data.txt","r",stdin) 31 #define gcd(a, b) __gcd(a,b) 32 #define lowbit(x) x&-x 33 #define IO iOS::sync_with_stdio(false) 34 35 36 using namespace std; 37 typedef long long LL; 38 typedef unsigned long long ULL; 39 const int maxn = 1e6 + 7; 40 const int maxm = 8e6 + 10; 41 const int INF = 0x3f3f3f3f; 42 const int mod = 1e9 + 7; 43 44 struct Aho_Corasick { 45 int next[500010][26], fail[500010], End[500010]; 46 int root, cnt; 47 48 int newnode() { 49 for (int i = 0; i < 26; i++) next[cnt][i] = -1; 50 End[cnt++] = 0; 51 return cnt - 1; 52 } 53 54 void init() { 55 cnt = 0; 56 root = newnode(); 57 } 58 59 void insert(char buf[]) { 60 int len = strlen(buf); 61 int now = root; 62 for (int i = 0; i < len; i++) { 63 if (next[now][buf[i] - 'a'] == -1) next[now][buf[i] - 'a'] = newnode(); 64 now = next[now][buf[i] - 'a']; 65 } 66 End[now]++; 67 } 68 69 void build() { 70 queue<int> Q; 71 fail[root] = root; 72 for (int i = 0; i < 26; i++) 73 if (next[root][i] == -1) next[root][i] = root; 74 else { 75 fail[next[root][i]] = root; 76 Q.push(next[root][i]); 77 } 78 while (!Q.empty()) { 79 int now = Q.front(); 80 Q.pop(); 81 for (int i = 0; i < 26; i++) 82 if (next[now][i] == -1) next[now][i] = next[fail[now]][i]; 83 else { 84 fail[next[now][i]] = next[fail[now]][i]; 85 Q.push(next[now][i]); 86 } 87 } 88 } 89 90 int query(char buf[]) { 91 int len = strlen(buf); 92 int now = root; 93 int res = 0; 94 for (int i = 0; i < len; i++) { 95 now = next[now][buf[i] - 'a']; 96 int temp = now; 97 while (temp != root) { 98 res += End[temp]; 99 End[temp] = 0; 100 temp = fail[temp]; 101 } 102 } 103 return res; 104 } 105 106 void debug() { 107 for (int i = 0; i < cnt; i++) { 108 printf("id = %3d,fail = %3d,end = %3d,chi = [", i, fail[i], End[i]); 109 for (int j = 0; j < 26; j++) printf("%2d", next[i][j]); 110 printf("]\n"); 111 } 112 } 113 }ac; 114 115 char buf[1000010]; 116 int T,n; 117 int main() { 118 sf(T); 119 while(T--){ 120 sf(n); 121 ac.init(); 122 for (int i = 0; i < n; ++i) { 123 scanf("%s",buf); 124 ac.insert(buf); 125 } 126 scanf("%s",buf); 127 ac.build(); 128 printf("%d\n",ac.query(buf)); 129 } 130 return 0; 131 }