【模板】AC自動機(加強版)
阿新 • • 發佈:2018-11-09
正題
這題也是非常的水。
先把模式串和文字串都插進字典樹中。
特殊的,給文字串經過的每一個位置都加1。
最後,建一次fail指標,然後一個節點的答案就是所有fail指標間接或直接指向它的權值和。
這個東西把fail指標的佇列反過來跑一遍就可以了。
因為一個節點的權值已經被後面的點更新完了。
記錄一下每一個模式串的結尾節點,比較那個節點答案即可。
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> using namespace std; int n; struct node{ int t,son[26],fail; }s[2000010]; int tot=0; char c[160][80]; char ch[1000010]; int id[1000010]; int list[2000010]; int insert(int op){ int x=0,l=strlen(ch+1); for(int i=1;i<=l;i++){ int temp=ch[i]-'a'; if(s[x].son[temp]==-1){ s[x].son[temp]=++tot; memset(s[tot].son,-1,sizeof(s[tot].son));s[tot].t=0;s[tot].fail=0; } x=s[x].son[temp]; s[x].t+=op; } return x; } void get_fail(){ int st=1,ed=2; list[st]=0; while(st<ed){ int x=list[st];st++; for(int i=0;i<26;i++){ int y=s[x].son[i]; if(y==-1) continue; int op=s[x].fail; while(op!=0 && s[op].son[i]==-1) op=s[op].fail; if(x!=0 && s[op].son[i]!=-1) s[y].fail=s[op].son[i]; list[ed++]=y; } } for(int i=ed-1;i>=1;i--) s[s[list[i]].fail].t+=s[list[i]].t; } int main(){ while(1){ scanf("%d",&n); if(n==0) break; tot=0;memset(s[0].son,-1,sizeof(s[0].son)); for(int i=1;i<=n;i++) scanf("%s",ch+1),strcpy(c[i]+1,ch+1),id[i]=insert(0); scanf("%s",ch+1);insert(1); get_fail(); int mmax=0; for(int i=1;i<=n;i++) mmax=max(mmax,s[id[i]].t); printf("%d\n",mmax); for(int i=1;i<=n;i++) if(s[id[i]].t==mmax) printf("%s\n",c[i]+1); } }