P3796 【模板】AC自动机(加强版)
P3796 【模板】AC自动机(加强版)
此题是在简单版的AC自动机基础上完成,直接附上代码
AC代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=1e6+5; string t[maxn],s[maxn]; struct tree { int fail;//失配指针 int son[26];//一个节点最多有26个子节点 int num;//标记以此节点为结尾 }DFA[maxn]; //字典树 int cnt=0; struct Result { int times; int pos; }ANS[maxn]; //记录单词出现次数 bool cmp(Result a,Result b) { if(a.times!=b.times) return a.times>b.times; else return a.pos<b.pos; } void clean(int x) { memset(DFA[x].son,0,sizeof(DFA[x].son)); DFA[x].fail=0; DFA[x].num=0; } void build(string s,int num) { int l=s.length(); int now=0;//字典树当前指针 for(int i=0;i<l;++i) { if(DFA[now].son[s[i]-'a']==0) //树上没有这个子节点 { DFA[now].son[s[i]-'a']=++cnt; //新增一个节点 clean(cnt); } now=DFA[now].son[s[i]-'a']; //向下构造 } DFA[now].num=num;// 标记单词的结尾 } void Get_fail() //构造fail指针 { queue<int> Q; for(int i=0;i<26;++i) { if(DFA[0].son[i]!=0) { DFA[DFA[0].son[i]].fail=0;//指向根节点,第二层 Q.push(DFA[0].son[i]); //压入队列 } } while(!Q.empty()) { int u=Q.front(); Q.pop(); for(int i=0;i<26;++i) //后面的层 { if(DFA[u].son[i]!=0)//如果存在此节点 { DFA[DFA[u].son[i]].fail=DFA[DFA[u].fail].son[i];//指向该节点的父节点的fail值对应的节点的相同子节点 Q.push(DFA[u].son[i]); //加入队列 } else //如果不存在这个节点 { DFA[u].son[i]=DFA[DFA[u].fail].son[i]; //当前节点的孩子节点指向当前节点的fail的孩子节点 } } } } void query(string s) { int len=s.size(); int now=0; for(int i=0;i<len;++i) { now=DFA[now].son[s[i]-'a'];//向下一层 for(int t=now;t;t=DFA[t].fail) //循环求解 ANS[DFA[t].num].times++; } } int main() { int n; while(1) { scanf("%d",&n); if(n==0) break; cnt=0; clean(0); for(int i=1;i<=n;++i) { cin>>s[i]; ANS[i].times=0; ANS[i].pos=i; build(s[i],i); } DFA[0].fail=0; //结束标志 Get_fail();//求出失配指针 cin>>s[0]; //文本串 query(s[0]); sort(ANS+1,ANS+n+1,cmp); printf("%d\n",ANS[1].times); cout << s[ANS[1].pos] << endl; for(int i=2;i<=n;++i) { if(ANS[i].times==ANS[i-1].times) cout<<s[ANS[i].pos]<<endl; else break; } } return 0; }