洛谷 P3808 【模板】AC自动机(简单版)洛谷 P3796 【模板】AC自动机(加强版)
https://www.cnblogs.com/gtarcoder/p/4820560.html
每个节点的后缀指针fail指针指向:
例如he,she,his,hers的例子(见蓝书P214):
7号点表示串his,将其头部去掉得到is但不存在该节点,再次将其头部去掉得到s,存在该节点,因此7号的后缀指针指向表示s的3号
5号点表示串she,将其头部去掉得到he,存在该节点,因此5号的后缀指针指向表示he的2号
从根节点到节点P可以得到一个字符串S,节点P的前缀指针定义为 指向树中出现过的S的最长后缀(不能等于S)
可以将trie上所有不存在的边u--(ch)-->v都补全为其fail指针指向的同类型边(f[u]--(ch)-->v'得到u--(ch)-->v')。(减少特判且方便递推)
每个节点的lst,与fail的区别在于,其指向的点表示的字符串一定是原来字符串集合中某一个完整的串(或空串),而fail则只要求原集合中某串的前缀即可
P3808中:由于只计算“出现过的”,所以某个算过贡献后要赋为0
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<queue> 5 using namespace std; 6 char *s[1001000],tttt[2000100],*sp=tttt,s2[1000100]; 7 int n; 8 //namespace AC 9 //{ 10 // int ch[1001000][26],sum[1001000],f[1001000],root,mem,lst[1000100]; 11 // void insert(char *x) 12 // { 13 // if(!root) root=++mem; 14 // int now=root,u; 15 // for(;*x;x++) 16 // { 17 // u=*x-'a'; 18 // if(!ch[now][u]) ch[now][u]=++mem; 19 // now=ch[now][u]; 20 // } 21 // sum[now]++; 22 // } 23 // void build() 24 // { 25 // int c,t,u,v; 26 // queue<int> q; 27 // f[root]=root; 28 // for(c=0;c<26;c++) 29 // { 30 // u=ch[root][c]; 31 // if(u) {f[u]=root;q.push(u);lst[u]=root;} 32 // } 33 // while(!q.empty()) 34 // { 35 // t=q.front();q.pop(); 36 // for(c=0;c<26;c++) 37 // { 38 // u=ch[t][c]; 39 // if(!u) {ch[t][c]=ch[f[t]][c];continue;} 40 // q.push(u); 41 // v=f[t]; 42 // while(v!=root&&!ch[v][c]) v=f[v]; 43 // f[u]=ch[v][c]; 44 // lst[u]=sum[u]?f[u]:lst[f[u]]; 45 // } 46 // } 47 // } 48 // void search(char *x) 49 // { 50 // int j=root; 51 // for(;*x;x++) 52 // { 53 // c=*x-'a'; 54 // if(sum[c]) 55 // } 56 // } 57 //} 58 //注释掉的是root任意值的情况,未完成,以下程序认为root为0号点 59 namespace AC 60 { 61 int ch[1001000][26],sum[1001000],f[1001000],mem,lst[1000100]; 62 void insert(char *x) 63 { 64 int now=0,u; 65 for(;*x;x++) 66 { 67 u=*x-'a'; 68 if(!ch[now][u]) ch[now][u]=++mem; 69 now=ch[now][u]; 70 } 71 sum[now]++; 72 } 73 void build() 74 { 75 int c,t,u; 76 queue<int> q; 77 f[0]=0; 78 for(c=0;c<26;c++) 79 { 80 u=ch[0][c]; 81 if(u) {f[u]=0;q.push(u);lst[u]=0;} 82 } 83 while(!q.empty()) 84 { 85 t=q.front();q.pop(); 86 for(c=0;c<26;c++) 87 { 88 u=ch[t][c]; 89 if(!u) {ch[t][c]=ch[f[t]][c];continue;} 90 q.push(u); 91 f[u]=ch[f[t]][c]; 92 lst[u]=sum[f[u]]?f[u]:lst[f[u]]; 93 } 94 } 95 } 96 int ans; 97 void get_ans(int j) 98 { 99 while(j) 100 { 101 ans+=sum[j]; 102 sum[j]=0; 103 j=lst[j]; 104 } 105 } 106 int count(char *x) 107 { 108 ans=0; 109 int j=0,c; 110 for(;*x;x++) 111 { 112 c=*x-'a'; 113 j=ch[j][c]; 114 get_ans(j); 115 } 116 return ans; 117 } 118 } 119 int main() 120 { 121 int i; 122 scanf("%d",&n); 123 for(i=1;i<=n;i++) 124 { 125 s[i]=sp;scanf("%s",s[i]);sp+=strlen(s[i])+1; 126 AC::insert(s[i]); 127 } 128 AC::build(); 129 scanf("%s",s2); 130 printf("%d",AC::count(s2)); 131 return 0; 132 }
P3796
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<queue> 5 #include<vector> 6 #include<map> 7 #include<string> 8 using namespace std; 9 char *s[160],tttt[20000],*sp,s2[1000100]; 10 int n; 11 namespace AC 12 { 13 int ch[20000][26],sum[20000],f[20000],mem,lst[20000],ans[20000]; 14 void clear() 15 { 16 int i,j; 17 for(i=0;i<=mem;i++) 18 { 19 for(j=0;j<26;j++) ch[i][j]=0; 20 sum[i]=f[i]=lst[i]=ans[i]=0; 21 } 22 mem=0; 23 } 24 int insert(char *x) 25 { 26 int now=0,u; 27 for(;*x;x++) 28 { 29 u=*x-'a'; 30 if(!ch[now][u]) ch[now][u]=++mem; 31 now=ch[now][u]; 32 } 33 sum[now]++; 34 return now; 35 } 36 void build() 37 { 38 int c,t,u; 39 queue<int> q; 40 f[0]=0; 41 for(c=0;c<26;c++) 42 { 43 u=ch[0][c]; 44 if(u) {f[u]=0;q.push(u);lst[u]=0;} 45 } 46 while(!q.empty()) 47 { 48 t=q.front();q.pop(); 49 for(c=0;c<26;c++) 50 { 51 u=ch[t][c]; 52 if(!u) {ch[t][c]=ch[f[t]][c];continue;} 53 q.push(u); 54 f[u]=ch[f[t]][c]; 55 lst[u]=sum[f[u]]?f[u]:lst[f[u]]; 56 } 57 } 58 } 59 void get_ans(int j) 60 { 61 while(j) 62 { 63 ans[j]+=sum[j]; 64 j=lst[j]; 65 } 66 } 67 void work(char *x) 68 { 69 int j=0,c; 70 for(;*x;x++) 71 { 72 c=*x-'a'; 73 j=ch[j][c]; 74 get_ans(j); 75 } 76 } 77 } 78 int pos[20000]; 79 int a1,anss; 80 int main() 81 { 82 int i; 83 while(1) 84 { 85 scanf("%d",&n); 86 if(n==0) break; 87 AC::clear(); 88 sp=tttt; 89 for(i=1;i<=n;i++) 90 { 91 s[i]=sp;scanf("%s",s[i]);sp+=strlen(s[i])+1; 92 pos[i]=AC::insert(s[i]); 93 } 94 AC::build(); 95 scanf("%s",s2); 96 AC::work(s2);a1=anss=0; 97 for(i=1;i<=n;i++) 98 if(AC::ans[pos[i]]>a1) 99 a1=AC::ans[pos[i]]; 100 for(i=1;i<=n;i++) 101 if(AC::ans[pos[i]]==a1) 102 anss++; 103 printf("%d\n",a1); 104 for(i=1;i<=n;i++) 105 if(AC::ans[pos[i]]==a1) 106 printf("%s\n",s[i]); 107 } 108 return 0; 109 }