P3796 【模板】AC自动机(加强版)
https://www.luogu.org/problemnew/show/P3796
题目描述
有NN个由小写字母组成的模式串以及一个文本串TT。每个模式串可能会在文本串中出现多次。你需要找出哪些模式串在文本串TT中出现的次数最多。
输入输出格式
输入格式:
输入含多组数据。
每组数据的第一行为一个正整数NN,表示共有NN个模式串,1 leq N leq 1501≤N≤150。
接下去NN行,每行一个长度小于等于7070的模式串。下一行是一个长度小于等于10^6106的文本串TT。
输入结束标志为N=0N=0。
输出格式:
对于每组数据,第一行输出模式串最多出现的次数,接下去若干行每行输出一个出现次数最多的模式串,按输入顺序排列。
输入输出样例
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 }