AC自动机--summer-work之我连模板题都做不出
Posted seaupnice
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AC自动机--summer-work之我连模板题都做不出相关的知识,希望对你有一定的参考价值。
这章对现在的我来说有点难,要是不写点东西,三天后怕是就一无所有了。
但写这个没有营养的blog的目的真的不是做题或提升,只是学习学习代码和理解一些概念。
现在对AC自动机的理解还十分浅薄,这里先贴上目前我看过的文章:
AC自动机相比Trie多了失配边,结点到结点间的状态转移,结点到根的状态转移。
这里fail的定义是:使当前字符失配时跳转到另一段从root开始每一个字符都与当前已匹配字符段某一个后缀完全相同且长度最大的位置继续匹配。
A - Keywords Search
题意:给多个模式串,求文本串中有多少模式串是子串。
这里直接贴上kuangbin大佬的模板。
1 #include <cstdio> 2 #include <algorithm> 3 #include <iostream> 4 #include <cstring> 5 #include <queue> 6 using namespace std; 7 struct Trie{ 8 int next[500010][26], fail[500010], end[500010]; 9 int root, L; 10 int newnode(){ 11 for(int i=0; i<26; i++){ 12 next[L][i] = -1; 13 } 14 end[L++] = 0; 15 return L-1; 16 } 17 void init(){ 18 L = 0; 19 root = newnode(); 20 } 21 void insert(char buf[]){ 22 int len = strlen(buf); 23 int now = root; 24 for(int i=0; i<len; i++){ 25 if(next[now][buf[i]-‘a‘] == -1){ 26 next[now][buf[i]-‘a‘] = newnode(); 27 } 28 now = next[now][buf[i]-‘a‘]; 29 } 30 end[now]++; 31 } 32 void build(){ 33 queue<int> Q; 34 fail[root] = root; 35 for(int i=0; i<26; i++){ 36 if(next[root][i] == -1){ 37 next[root][i] = root; 38 }else{ 39 fail[next[root][i]] = root; 40 Q.push(next[root][i]); 41 } 42 } 43 while( !Q.empty() ){ 44 int now = Q.front(); 45 Q.pop(); 46 for(int i=0; i<26; i++){ 47 if(next[now][i] == -1){ 48 next[now][i] = next[fail[now]][i]; 49 }else{ 50 fail[next[now][i]] = next[fail[now]][i]; 51 Q.push(next[now][i]); 52 } 53 } 54 } 55 } 56 int query(char buf[]){ 57 int len = strlen(buf); 58 int now = root; 59 int res = 0; 60 for(int i=0; i<len; i++){ 61 now = next[now][buf[i]-‘a‘]; 62 int temp = now; 63 while(temp != root){ 64 res += end[temp]; 65 end[temp] = 0; 66 temp = fail[temp]; 67 } 68 } 69 return res; 70 } 71 void debug(){ 72 for(int i=0; i<L; i++){ 73 cout << "id = " << i << " " << "fail = " << fail[i] << " " << "end = " << end[i] << endl; 74 for(int j=0; j<26; j++){ 75 cout << next[i][j] << " "; 76 } 77 cout << endl; 78 } 79 } 80 }; 81 char buf[1000010]; 82 Trie ac; 83 int main(){ 84 freopen("in.txt", "r", stdin); 85 int T; 86 scanf("%d", &T); 87 while(T--){ 88 int n; 89 scanf("%d", &n); 90 ac.init(); 91 for(int i=0; i<n; i++){ 92 scanf("%s", buf); 93 ac.insert(buf); 94 } 95 ac.build(); 96 scanf("%s", buf); 97 cout << buf << endl; 98 printf("%d ", ac.query(buf)); 99 } 100 return 0; 101 }
C - L语言
我把学习心得放在这里了
D - Computer Virus on Planet Pandora
题意:给一个文本串,求其正反两个串中出现了几个模式串。
这里AC自动机中query()操作的作用:查询Trie中有几个前缀出现在文本串中。
方法是遍历Trie树找val=1的点即字符串最后一个字符,然后计数,同时要通过fail找回边,这里就是kmp的意味了。
所以才有人说AC自动机 = Trie+Kmp。
1 #include <cstdio> 2 #include <algorithm> 3 #include <iostream> 4 #include <cstring> 5 #include <queue> 6 using namespace std; 7 #define mst(s, t) memset(s, 0, sizeof(s)); 8 struct Trie{ 9 int ch[250110][26], fail[250010], val[250110]; 10 int res, sz; 11 inline void init(){ sz=1; mst(ch[0], 0); mst(val, 0); } 12 inline int idx(char c) { return c-‘A‘; } 13 inline void insert(char *s){ 14 int u = 0, n = strlen(s); 15 for(int i=0; i<n; i++){ 16 int c = idx(s[i]); 17 if(!ch[u][c]){ 18 mst(ch[sz], 0); 19 ch[u][c] = sz++; 20 } 21 u = ch[u][c]; 22 } 23 val[u] = 1; 24 } 25 inline void build(){ 26 queue<int> Q; 27 int u; fail[0] = 0; 28 for(int i=0; i<26; i++){ 29 u = ch[0][i]; 30 if(u){ fail[u]=0; Q.push(u); } 31 } 32 while( !Q.empty() ){ 33 int now = Q.front(); Q.pop(); 34 for(int i=0; i<26; i++){ 35 u = ch[now][i]; 36 if(!u){ ch[now][i] = ch[fail[now]][i]; continue; } 37 Q.push(u); 38 int v = fail[now]; 39 while(v && !ch[v][i]) v=fail[v]; 40 fail[u] = ch[v][i]; 41 } 42 } 43 } 44 inline int query(char *buf, int len){ 45 int u = 0, res = 0; 46 for(int i=0; i<len; i++){ 47 int c = idx(buf[i]); 48 u = ch[u][c]; 49 int temp = u; 50 //有几个前缀出现在文本串中 51 while(temp && val[temp]!=0){ 52 res += val[temp]; 53 val[temp] = 0; 54 temp = fail[temp]; 55 } 56 } 57 return res; 58 } 59 }; 60 char tmp[5100010], buf[5100010]; 61 Trie ac; 62 int main(){ 63 // freopen("in.txt", "r", stdin); 64 int T; 65 scanf("%d", &T); 66 while(T--){ 67 ac.init(); 68 int n; 69 scanf("%d", &n); 70 for(int i=0; i<n; i++){ 71 scanf("%s", buf); 72 ac.insert(buf); 73 } 74 ac.build(); 75 scanf("%s", tmp); 76 int tlen = strlen(tmp), blen=0; 77 for(int i=0; i<tlen; i++){ 78 if(tmp[i]==‘[‘){ 79 i++; 80 int cnt = 0; 81 while(tmp[i] >= ‘0‘ && tmp[i] <= ‘9‘){ 82 cnt = cnt*10 + tmp[i++]-‘0‘; 83 } 84 for(int k=0; k<cnt; k++){ 85 buf[blen++] = tmp[i]; 86 } 87 i++; 88 }else{ 89 buf[blen++] = tmp[i]; 90 } 91 } 92 tmp[blen] = ‘