洛谷 P3796 【模板】AC自动机(加强版)(AC自动机)

题目链接:https://www.luogu.com.cn/problem/P3796

 

AC自动机:复杂度$O( (N+M)\times L )$,N为模式串个数,L为平均长度,M为文章长度。

 

insert:

  构造一个trie,然后标记一下每一个模式串的最后一个,即$vis$。

 

get_fail:

  进行在trie上进行BFS,第一层点的失配指针指向根节点;之后的一个节点失配指针指向/他父亲的失配指针/指向的节点中/的儿子具有相同节点的位置。

  这里有一个小优化:fail是用来寻找失配时走到的位置的,走一个点fail的他的ch[i]一定是没有的。那么可以用这些ch指针直接指向它的fail的ch[i],可以发现这样操作之后,每个点的ch[i]直接指向了原本沿着失配边不停走的最终结果,这样的话,匹配时每次用ch指针的对象即可,不用一直沿fail边走看看这个点有没有ch[i]了。

 

query:

  向下一层循环求解,直到fail不能走了,注意如果j不是终点,那么即ans[0]++,但最终不影响结果,因为统计时从1开始...

 

AC代码:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<queue>
 6 using namespace std;
 7 const int N=1000000+100;
 8 const int maxn=505;
 9 int fail[N],ch[N][26],vis[N];
10 int ans[N];
11 string s[maxn];
12 int cnt;
13 void insert(string s,int v){
14     int u=0;
15     int len=s.length();
16     for(int i=0;i<len;i++){
17         int id=s[i]-'a';
18         if(!ch[u][id]) ch[u][id]=++cnt;
19         u=ch[u][id];
20     }
21     vis[u]=v;
22 }
23 void get_fail(){
24     int now=0;
25     queue<int> q;
26     for(int i=0;i<26;i++){
27         if(ch[now][i]){
28             q.push(ch[now][i]);
29             fail[ch[now][i]]=now;
30         }
31     }
32     while(!q.empty()){
33         int u=q.front();
34         q.pop();
35         for(int i=0;i<26;i++){
36             int v=ch[u][i];
37             if(v) fail[v]=ch[fail[u]][i],q.push(v);
38             else ch[u][i]=ch[fail[u]][i];//you hua
39         }
40     }
41 }
42 void query(string s){
43     int now=0;
44     int len=s.length();
45     for(int i=0;i<len;i++){
46         now=ch[now][s[i]-'a'];
47         for(int j=now;j;j=fail[j]) ans[vis[j]]++;
48     }
49 }
50 int main(){
51     int n;
52     while(scanf("%d",&n)){
53         memset(vis,0,sizeof(vis));
54         memset(ans,0,sizeof(ans));
55         memset(ch,0,sizeof(ch));
56         memset(fail,0,sizeof(fail));
57         if(n==0) break;
58         for(int i=1;i<=n;i++){
59             cin>>s[i];
60             insert(s[i],i);
61         }
62         get_fail();
63         string str;
64         cin>>str;
65         query(str);
66         int maxx=0;
67         for(int i=1;i<=n;i++) maxx=max(maxx,ans[i]);
68         printf("%d\n",maxx);
69         for(int i=1;i<=n;i++) if(ans[i]==maxx) cout<<s[i]<<endl;
70     }
71     return 0;
72 }
AC代码

 

posted @ 2020-02-23 22:43  dfydn  阅读(158)  评论(0编辑  收藏  举报