AC自動機模板(洛谷P3796)
阿新 • • 發佈:2018-12-19
題目描述
有N個由小寫字母組成的模式串以及一個文字串T。每個模式串可能會在文字串中出現多次。你需要找出哪些模式串在文字串T中出現的次數最多。
輸入格式:
輸入含多組資料。
每組資料的第一行為一個正整數N,表示共有N個模式串,1≤N≤150。
接下去N行,每行一個長度小於等於70的模式串。下一行是一個長度小於等於10^6的文字串T。
輸入結束標誌為N=0。
輸出格式:
對於每組資料,第一行輸出模式串最多出現的次數,接下去若干行每行輸出一個出現次數最多的模式串,按輸入順序排列。
2 aba bab ababababac 6 beta alpha haha delta dede tata dedeltalphahahahototatalpha 0
4 aba 2 alpha haha
#include<bits/stdc++.h> using namespace std; const int Maxn=1000005; struct Answer{ int cnt,Index; bool operator <(const Answer&rhs)const{ return cnt>rhs.cnt||cnt==rhs.cnt&&Index<rhs.Index; } }ans[155]; struct Trie{ struct node{ int num,fail,Index;map<int,int>son; }a[Maxn]; int cnt,root; map<int,int>::iterator it; #define son(x,y) a[x].son[y] void init(){ for(int i=0;i<=cnt;++i){ a[i]=(node){0,0,0}; a[i].son.clear(); } root=cnt=0; } void insert(char *s,int Index){ int x=root,len=strlen(s)-1; for(int i=0;i<=len;++i){ x=(son(x,s[i])=son(x,s[i])?:++cnt); } if(!a[x].Index)a[x].Index=Index; ++a[x].num; } void Fail(){ queue<int>Q; for(it=a[root].son.begin();it!=a[root].son.end();++it) Q.push(it->second); for(int j;!Q.empty();){ int x=Q.front();Q.pop(); for(it=a[x].son.begin();it!=a[x].son.end();++it){ for(j=a[x].fail;j&&!son(j,it->first);j=a[j].fail); a[it->second].fail=son(j,it->first); Q.push(it->second); } } } void Match(char *s){ int x=root,len=strlen(s)-1; for(int i=0;i<=len;++i){ while(x&&!son(x,s[i]))x=a[x].fail; x=son(x,s[i]); for(int t=x;t;t=a[t].fail) ans[a[t].Index].cnt+=a[t].num; } } }trie; char s[Maxn],t[155][75]; int main(){ int n;while(scanf("%d",&n)!=EOF&&n){ trie.init(); for(int i=1;i<=n;++i){ scanf("%s",&t[i]); trie.insert(t[i],i); } trie.Fail(); for(int i=1;i<=n;++i) ans[i]=(Answer){0,i}; scanf("%s",s); trie.Match(s); sort(ans+1,ans+n+1); int maxcnt=ans[1].cnt; cout<<maxcnt<<'\n'; for(int i=1;i<=n;++i){ if(ans[i].cnt!=maxcnt)break; cout<<t[ans[i].Index]<<'\n'; } } return 0; }