题目:P3808:https://www.luogu.org/problemnew/show/P3808
P3796:https://www.luogu.org/problemnew/show/P3796
从这里学了下AC自动机:http://www.cnblogs.com/cjyyb/p/7196308.html
我的理解大概就是构建一棵由模式串组成的 Trie 树,然后把文本串一节一节放在上面查找;
失配指针指向的是结尾字母和自己一样的、Trie 树上的其他分支,大约就是在找后缀这样的感觉;
所以文本串每加入一个字符,就在 Trie 树上查找以这个字符结尾的后缀模式串,所以能找到所有出现过的;
慕名已久的AC自动机原来也挺简单的嘛!
代码如下:
P3808:
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; int const maxn=1e6+5; int n,cnt; queue<int>q; struct N{ int fail,son[26],end; }AC[maxn]; void build(string s) { int l=s.length(); int nw=0; for(int i=0;i<l;i++) { if(AC[nw].son[s[i]-'a']==0)AC[nw].son[s[i]-'a']=++cnt; nw=AC[nw].son[s[i]-'a']; } AC[nw].end++; } void get_fail() { AC[0].fail=0; for(int i=0;i<26;i++) { if(AC[0].son[i]==0)continue; AC[AC[0].son[i]].fail=0; q.push(AC[0].son[i]); } while(q.size()) { int x=q.front(); q.pop(); for(int i=0;i<26;i++) { if(AC[x].son[i]) { AC[AC[x].son[i]].fail=AC[AC[x].fail].son[i]; q.push(AC[x].son[i]); } else AC[x].son[i]=AC[AC[x].fail].son[i]; } } } int query(string s) { int l=s.length(); int ret=0,nw=0; for(int i=0;i<l;i++) { nw=AC[nw].son[s[i]-'a']; for(int t=nw;t&&AC[t].end!=-1;t=AC[t].fail) { ret+=AC[t].end; AC[t].end=-1; } } return ret; } int main() { scanf("%d",&n); string s; for(int i=1;i<=n;i++) { cin>>s; build(s); } get_fail(); cin>>s; printf("%d ",query(s)); return 0; }
P3796:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> using namespace std; int const maxn=1e6+5; int n,cnt; queue<int>q; string s[155]; struct N{ int son[26],fail,end; }AC[maxn]; struct P{int num,pos;}ans[155]; bool cmp(P x,P y) { if(x.num==y.num)return x.pos<y.pos; else return x.num>y.num; } void clear(int x) { memset(AC[x].son,0,sizeof AC[x].son); AC[x].fail=0; AC[x].end=0; } void build(string s,int num) { int l=s.length(); int nw=0; for(int i=0;i<l;i++) { if(!AC[nw].son[s[i]-'a'])AC[nw].son[s[i]-'a']=++cnt,clear(cnt); nw=AC[nw].son[s[i]-'a']; } AC[nw].end=num; } void get_fail() { while(q.size())q.pop(); AC[0].fail=0; for(int i=0;i<26;i++) { if(AC[0].son[i]==0)continue; AC[AC[0].son[i]].fail=0; q.push(AC[0].son[i]); } while(q.size()) { int x=q.front(); q.pop(); for(int i=0;i<26;i++) { if(AC[x].son[i]) { AC[AC[x].son[i]].fail=AC[AC[x].fail].son[i]; q.push(AC[x].son[i]); } else AC[x].son[i]=AC[AC[x].fail].son[i]; } } } void query(string s) { int l=s.length(); int nw=0; for(int i=0;i<l;i++) { nw=AC[nw].son[s[i]-'a']; for(int t=nw;t/*&&t.end!=-1*/;t=AC[t].fail) { ans[AC[t].end].num++; // AC[t].end=-1; } } } int main() { while(1) { scanf("%d",&n); if(!n)return 0; cnt=0; clear(0); for(int i=1;i<=n;i++) { cin>>s[i]; build(s[i],i); ans[i].pos=i; ans[i].num=0;// } get_fail(); cin>>s[0]; query(s[0]); sort(ans+1,ans+n+1,cmp); printf("%d ",ans[1].num); cout<<s[ans[1].pos]<<endl; for(int i=2;i<=n;i++) { if(ans[i].num==ans[i-1].num) cout<<s[ans[i].pos]<<endl; else break; } } }