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

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

https://www.luogu.org/problemnew/show/P3796

题目描述

NN个由小写字母组成的模式串以及一个文本串TT。每个模式串可能会在文本串中出现多次。你需要找出哪些模式串在文本串TT中出现的次数最多。

输入输出格式

输入格式:

 

输入含多组数据。

每组数据的第一行为一个正整数NN,表示共有NN个模式串,1 \leq N \leq 1501N150。

接下去NN行,每行一个长度小于等于7070的模式串。下一行是一个长度小于等于10^6106的文本串TT。

输入结束标志为N=0N=0。

 

输出格式:

 

对于每组数据,第一行输出模式串最多出现的次数,接下去若干行每行输出一个出现次数最多的模式串,按输入顺序排列。

 

输入输出样例

输入样例#1: 
2
aba
bab
ababababac
6
beta
alpha
haha
delta
dede
tata
dedeltalphahahahototatalpha
0
输出样例#1: 
4
aba
2
alpha
haha

 

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define lson l,mid,rt<<1
  4 #define rson mid+1,r,rt<<1|1
  5 #define sqr(x) ((x)*(x))
  6 #define maxn 1000005
  7 typedef long long ll;
  8 typedef unsigned long long ull;
  9 const ull MOD=257;
 10 /*#ifndef ONLINE_JUDGE
 11         freopen("1.txt","r",stdin);
 12 #endif */
 13 
 14 struct tree{
 15     int fail;
 16     int vis[26];
 17     int num;
 18 }ac[1000005];
 19 
 20 int cnt=0;
 21 
 22 struct ANS{
 23     int num,pos;
 24     bool operator<(const ANS &b){
 25         if(num==b.num) return pos<b.pos;
 26         return num>b.num;
 27     }
 28 }ans[155];
 29 
 30 void Clear(int x){
 31     memset(ac[x].vis,0,sizeof(ac[0].vis));
 32     ac[x].num=ac[x].fail=0;
 33 }
 34 
 35 void build(string s,int flag){///建trie树
 36     int len=s.length();
 37     int now=0;
 38     for(int i=0;i<len;i++){
 39         if(ac[now].vis[s[i]-'a']==0){
 40             ac[now].vis[s[i]-'a']=++cnt;
 41             Clear(cnt);
 42         }
 43         now=ac[now].vis[s[i]-'a'];
 44     }
 45     ac[now].num=flag;
 46 }
 47 
 48 void get_fail(){///构建成trie图
 49     queue<int>Q;
 50     ac[0].fail=0;
 51     for(int i=0;i<26;i++){
 52         if(ac[0].vis[i]){
 53             ac[ac[0].vis[i]].fail=0;
 54             Q.push(ac[0].vis[i]);
 55         }
 56     }
 57     while(!Q.empty()){
 58         int u=Q.front();
 59         Q.pop();
 60         for(int i=0;i<26;i++){
 61             if(ac[u].vis[i]){
 62                 ac[ac[u].vis[i]].fail=ac[ac[u].fail].vis[i];
 63                 Q.push(ac[u].vis[i]);
 64             }
 65             else{
 66                 ac[u].vis[i]=ac[ac[u].fail].vis[i];///如果当前结点不存在,就指向父亲结点的fail指向的结点的子结点
 67             }
 68         }
 69     }
 70 }
 71 
 72 void ac_query(string s){
 73     int len=s.length();
 74     int now=0;
 75     for(int i=0;i<len;i++){
 76         now=ac[now].vis[s[i]-'a'];
 77         for(int t=now;t&&ac[t].num!=-1;t=ac[t].fail){
 78             ans[ac[t].num].num++;
 79         }
 80     }
 81 }
 82 
 83 string s[155];
 84 
 85 int main(){
 86     #ifndef ONLINE_JUDGE
 87         freopen("1.txt","r",stdin);
 88     #endif
 89     std::ios::sync_with_stdio(false);
 90     int n;
 91     while(cin>>n){
 92         if(!n) break;
 93         Clear(0);
 94         for(int i=1;i<=n;i++){
 95             cin>>s[i];
 96             build(s[i],i);
 97             ans[i].num=0;
 98             ans[i].pos=i;
 99         }
100         get_fail();
101         cin>>s[0];
102         ac_query(s[0]);
103         sort(ans+1,ans+n+1);
104         cout<<ans[1].num<<endl;
105         cout<<s[ans[1].pos]<<endl;
106         for(int i=2;i<=n;i++){
107             if(ans[i].num==ans[i-1].num){
108                 cout<<s[ans[i].pos]<<endl;
109             }
110             else{
111                 break;
112             }
113         }
114     }
115 }
View Code

 

posted on 2019-02-12 00:31  Fighting_sh  阅读(137)  评论(0编辑  收藏  举报

导航