【题目链接】
https://www.luogu.org/problem/P3808
【题意】
给定n个模式串和1个文本串,求有多少个模式串在文本串里出现过。
【题解】
不再介绍基础知识了,就是裸的模板题,直接贴上来。
【代码】

1 #include<queue>
2 #include<cstdio>
3 #include<cstring>
4 #include<algorithm>
5 using namespace std;
6 const int N = 5e5+100;
7 const int M = 1e6+10;
8 queue < int > Q ;
9 typedef struct Aho_Corasick_Automaton{
10 int Son[N][26],End[N],Fail[N],idx;
11 void Init(){
12 idx = 0 ;
13 while( !Q.empty() ) Q.pop() ;
14 memset(Son , 0 , sizeof Son );
15 memset(End , 0 , sizeof End );
16 memset(Fail, 0 , sizeof Fail );
17 }
18 void Insert(char s[]){
19 int p = 0 ;
20 for(int i=0;s[i];i++){
21 int t = s[i] - 'a';
22 if( !Son[p][t] )
23 Son[p][t] = ++idx;
24 p = Son[p][t] ;
25 }
26 End[p] ++ ;
27 }
28
29 void Build(){
30 for(int i=0;i<26;i++){
31 if( Son[0][i] )
32 Fail[Son[0][i]] = 0 ,Q.push(Son[0][i]);
33 }
34
35 while( !Q.empty() ){
36 int u = Q.front() ;
37 Q.pop();
38
39 for(int i=0;i<26;i++){
40 if( Son[u][i] ){
41 Fail[Son[u][i]] = Son[Fail[u]][i] ;
42 Q.push( Son[u][i] );
43 }else{
44 Son[u][i] = Son[Fail[u]][i];
45 }
46 }
47 }
48 }
49
50 void Query(char s[]){
51 int p = 0,res = 0;
52 for(int i=0;s[i];i++){
53 int t = s[i] - 'a';
54 p = Son[p][t] ;
55 for(int j=p ; j && ~End[j] ; j = Fail[j] ){
56 res += End[j] ;
57 End[j] = -1 ;
58 }
59 }
60 printf("%d\n",res);
61 }
62 }AC_Machine ;
63 AC_Machine AC ;
64 char s[M];
65 int n;
66 int main(){
67
68 scanf("%d",&n);
69 //AC.Init();
70
71 for(int i=0;i<n;i++){
72 scanf("%s",s);
73 AC.Insert(s);
74 }
75 AC.Build();
76 scanf("%s",s);
77 AC.Query(s);
78 return 0;
79 }
【题目链接】
https://www.luogu.org/problem/P3796
【题意】
有N个由小写字母组成的模式串以及一个文本串T。每个模式串可能会在文本串中出现多次。你需要找出哪些模式串在文本串T中出现的次数最多。
和模板题1一样,就是最后结尾的标记加上一些小改动。
【代码】

1 // luogu-judger-enable-o2
2 #pragma GCC optimize(2)
3
4 #include<queue>
5 #include<cstdio>
6 #include<cstring>
7 #include<iostream>
8 #include<algorithm>
9 using namespace std;
10 const int N = 5e5+1e4;
11 const int M = 1e6+10;
12 char Str[200][100],s[M];
13 int Cnt[N],vis[N],n;
14 queue < int > Q ;
15 typedef struct Aho_Corasick_Automaton{
16 int Son[N][26],End[N],Fail[N],idx;
17 void Init(){
18 idx = 0 ;
19 while( !Q.empty() ) Q.pop() ;
20 memset(Cnt , 0 , sizeof Cnt );
21 memset(vis , 0 , sizeof vis );
22 memset(Son , 0 , sizeof Son );
23 memset(End , 0 , sizeof End );
24 memset(Fail, 0 , sizeof Fail );
25 }
26 void Insert(char s[],int Id ){
27 int p = 0 ;
28 for(int i=0;s[i];i++){
29 int t = s[i] - 'a';
30 if( !Son[p][t] )
31 Son[p][t] = ++idx;
32 p = Son[p][t] ;
33 }
34 End[p] ++ ;
35 vis[p] = Id;
36 }
37
38 void Build(){
39 for(int i=0;i<26;i++){
40 if( Son[0][i] )
41 Fail[Son[0][i]] = 0 ,Q.push(Son[0][i]);
42 }
43
44 while( !Q.empty() ){
45 int u = Q.front() ;
46 Q.pop();
47
48 for(int i=0;i<26;i++){
49 if( Son[u][i] ){
50 Fail[Son[u][i]] = Son[Fail[u]][i] ;
51 Q.push( Son[u][i] );
52 }else{
53 Son[u][i] = Son[Fail[u]][i];
54 }
55 }
56 }
57 }
58
59 void Query(char s[]){
60 int p = 0,res = 0;
61 for(int i=0;s[i];i++){
62 int t = s[i] - 'a';
63 p = Son[p][t] ;
64 for(int j=p ; j ; j = Fail[j] ){
65 if( End[j] ){
66 Cnt[vis[j]] ++ ;
67 }
68 }
69 }
70 for(int i=0;i<n;i++){
71 res = max( Cnt[i] , res ) ;
72 }
73 cout << res << endl;
74 //printf("%d\n",res);
75 for(int i=0;i<n;i++){
76 if( res == Cnt[i] ){
77 cout << Str[i] << endl;
78 }
79 }
80 }
81 }AC_Machine ;
82 AC_Machine AC ;
83
84 int main(){
85
86 ios_base :: sync_with_stdio(false);
87 cin.tie(NULL) , cout.tie(NULL);
88
89 while ( cin >> n ,n ){
90 AC.Init();
91 for(int i=0;i<n;i++){
92 //scanf("%s",s);
93 cin >> Str[i];
94 AC.Insert(Str[i],i);
95 }
96 AC.Build();
97 //scanf("%s",s);
98 cin >> s ;
99 AC.Query(s);
100 }
101 return 0;
102 }
【题目链接】
https://www.luogu.org/problem/P5357
【题意】
给你一个文本串 SS 和 nn 个模式串 T_{1..n},请你分别求出每个模式串 Ti 在 S 中出现的次数。
【题解】
这个题目就非常有意思了,
其实我还没怎么想就去洛谷看题解了,
发现是还是各显神通呀。大家都很厉害,我这里提供三个人的做法。
其实道理都是一样的。
一种是:进行类似于差分累加的过程。

1 #include<queue>
2 #include<cstdio>
3 #include<cstring>
4 #include<iostream>
5 #include<algorithm>
6 using namespace std;
7 const int N = 2e5+10;
8 const int M = 2e6+10;
9 typedef struct node{
10 int son[26],fail;
11 int& operator [] (int x) {return son[x];}
12 }Node;
13
14 Node Trie[N];
15
16 int Q[N],head[N],Next[N],Ans[N],d[N];
17 int Head,Tail,n,idx;
18 char s[M];
19
20 void Insert(char s[],int Id ){
21 int p = 0 ;
22 for(int i=0;s[i];i++){
23 int t = s[i] - 'a';
24 if( !Trie[p][t] )
25 Trie[p][t] = ++idx;
26 p = Trie[p][t] ;
27 }
28 Next[Id] = head[p] ;
29 head[p] = Id;
30 }
31
32 void Build(){
33 Head = 1 , Tail = 0;
34 for(int i=0;i<26;i++) if( Trie[0][i] ) Q[++Tail] = Trie[0][i];
35 while( Head <= Tail ){
36 int u = Q[Head++] ;
37 for(int i=0;i<26;i++){
38 if( Trie[u][i] ){
39 Trie[Trie[u][i]].fail = Trie[Trie[u].fail][i] ;
40 Q[++Tail] = Trie[u][i] ;
41 }else{
42 Trie[u][i] = Trie[Trie[u].fail][i];
43 }
44 }
45 }
46 }
47
48 void Query(char s[]){
49 int p = 0,res = 0;
50 for(int i=0;s[i];i++){
51 int t = s[i] - 'a';
52 p = Trie[p][t] ;
53 d[p] ++ ;
54 }
55 for(int i=idx;i;i--){
56 for(int j=head[Q[i]] ; j ; j = Next[j] ) Ans[j] = d[Q[i]];
57 d[ Trie[Q[i]].fail ] += d[ Q[i] ];
58 }
59 for(int i=1;i<=n;i++){
60 cout << Ans[i] << endl ;
61 }
62 }
63
64 int main(){
65
66 ios_base :: sync_with_stdio(false);
67 cin.tie(NULL) , cout.tie(NULL);
68
69 cin >> n;
70 for(int i=1;i<=n;i++){
71 cin >> s;
72 Insert(s,i);
73 }
74 Build();
75 cin >> s ;
76 Query(s);
77 return 0;
78 }
一种是拓扑排序的做法

1 #include<bits/stdc++.h>
2 using namespace std;
3 const int N = 2e6+10;
4 typedef struct Node {
5 int son[26],Fail,End,Cnt;
6 void Clear(){
7 memset(son,0,sizeof son );
8 Fail = End = Cnt = 0 ;
9 }
10 int & operator [] (int x){ return son[x];}
11 }Node ;
12 Node Trie[N];
13 char s[N];
14 int Ans,idx=1,n,Head,Tail;
15 int Mp[N],vis[N],Ind[N],Q[N];
16
17 void Insert( char s[] , int Id ){
18 int p = 1 ;
19 for(int i=0;s[i];i++){
20 int t = s[i] - 'a';
21 if( !Trie[p][t] )
22 Trie[p][t] = ++idx ;
23 p = Trie[p][t] ;
24 }
25 if( !Trie[p].End ) Trie[p].End = Id;
26 Mp[Id] = Trie[p].End
27 ;
28 }
29
30 void Build(){
31 Head = 1 , Tail = 0 ;
32 for(int i=0;i<26;i++){ Trie[0][i] = 1 ; }
33 Q[++Tail] = 1 ;
34 while( Head <= Tail ){
35 int u = Q[Head++] ;
36 for(int i=0;i<26;i++){
37 int To = Trie[u][i] ;
38 if( To ){
39 Trie[To].Fail = Trie[Trie[u].Fail][i];
40 Ind[ Trie[To].Fail ] ++ ;
41 Q[++Tail] = Trie[u][i];
42 }else{
43 Trie[u][i] = Trie[Trie[u].Fail][i];
44 }
45 }
46 }
47 }
48 void Topu( ){
49 Head = 1 , Tail = 0 ;
50 for(int i=1;i<=idx;i++) if( !Ind[i] ) Q[++Tail] = i;
51
52 while( Head <= Tail ){
53 int u = Q[Head++];
54 vis[ Trie[u].End ] = Trie[u].Cnt ;
55 int To = Trie[u].Fail ;
56 Ind[To] -- ;
57 Trie[To].Cnt += Trie[u].Cnt;
58 if( Ind[To] == 0 )
59 Q[++Tail] = To ;
60 }
61 }
62 void Query(char s[]){
63 int p = 1 ;
64 for(int i=0;s[i];i++){
65 p = Trie[p][s[i]-'a'];
66 Trie[p].Cnt ++ ;
67 }
68 }
69
70 int main()
71 {
72 scanf("%d",&n);
73 for(int i=1;i<=n;i++){
74 scanf("%s",s);
75 Insert( s, i );
76 }
77 Build() ;
78 scanf("%s",s);
79 Query(s);
80 Topu();
81 for(int i=1;i<=n;i++){
82 printf("%d\n",vis[Mp[i]]);
83 }
84 }
85
86 /*
87
88
89 5
90 a
91 bb
92 aa
93 abaa
94 abaaa
95 abaaabaa
96
97 6
98 0
99 3
100 2
101 1
102
103 */
最后一种是最正宗的做法了,建fail树。

1 #include<bits/stdc++.h>
2 using namespace std;
3
4 const int N = 2e6+10;
5 void dfs(int u);
6 void Add_edge(int u,int v);
7
8 char s[N];
9 int head[N],nxt[N],to[N], cnt ;
10
11 int n,idx=1;
12 int Trie[N][26],fail[N],Match[N],Sz[N];
13
14 int Q[N],Head,Tail;
15
16 void Insert(char s[] ,int Id){
17 int p = 1 ;
18 for(int i=0;s[i];i++){
19 int t = s[i]-'a';
20 if( !Trie[p][t] ){
21 Trie[p][t] = ++idx;
22 }
23 p = Trie[p][t] ;
24 }
25 Match[Id] = p ;
26 }
27 void Build(){
28 Head = 1 , Tail = 0 ;
29 for(int i=0;i<26;i++)
30 Trie[0][i] = 1 ;
31 Q[++Tail] = 1 ;
32 while( Head <= Tail ){
33 int u = Q[Head++] ;
34 for(int i=0;i<26;i++){
35 if( Trie[u][i] ){
36 fail[Trie[u][i]] = Trie[fail[u]][i];
37 Q[++Tail] = Trie[u][i];
38 }else{
39 Trie[u][i] = Trie[fail[u]][i];
40 }
41 }
42 }
43 }
44 void Query(char s[]){
45 for(int p=1,i=0;s[i];i++){
46 p = Trie[p][s[i]-'a'];
47 Sz[p] ++ ;
48 }
49 for(int i=2;i<=idx;i++){
50 Add_edge( fail[i] , i );
51 }
52 dfs( 1 );
53 for(int i=1;i<=n;i++){
54 printf("%d\n",Sz[Match[i]]);
55 }
56 }
57 int main()
58 {
59 scanf("%d",&n);
60 for(int i=1;i<=n;i++){
61 scanf("%s",s);
62 Insert(s,i);
63 }
64 Build();
65 scanf("%s",s);
66 Query(s);
67 return 0;
68 }
69 void dfs(int u){
70 for(int i=head[u];i;i=nxt[i]){
71 int v = to[i] ;
72 dfs(v);
73 Sz[u] += Sz[v];
74 }
75 }
76 void Add_edge(int u,int v){
77 nxt[++cnt]= head[u];
78 head[u] = cnt ;
79 to[cnt] = v ;
80 }
81
82
83 /*
84
85 5
86 a
87 bb
88 aa
89 abaa
90 abaaa
91 abaaabaa
92
93
94 6
95 0
96 3
97 2
98 1
99
100 */
