【题解】P3796 【模板】AC自动机(加强版)
记录当前\(cnt\)是第几个"星"。记录第几个串是对应着第几个星。
这里补充一点对于\(AC\)自动机的理解。可能一直有个问题我没有想明白,就是打标记的点只有一个,然而匹配时,假若一个分支包括了另一个不同的分支该怎么办。实际上,我们可以在匹配的时候使用\(fail\)数组进行类似链式前向星的遍历,从而遍历到那个打标记的地方。那么问题来了,怎么保证链式前向星会遍历到那个打了标记的节点呢?答案就在\(gen\_fail\)的玄机里。\(gen\_fail\)时,由于是找和已经匹配部分相同的后缀,所以指向的节点它到\(0\)的长度会越来越小。显然那个有标记点的串是相较其它包括它自己的串中最短的,那么一定会被这个链式前向星遍历到。
上代码
#include<bits/stdc++.h>
using namespace std;
#define RP(t,a,b) for(register int t=(a),edd=(b);t<=edd;++t)
#define DRP(t,a,b) for(register int t=(a),edd=(b);t>=edd;--t)
#define ERP(t,a) for(register int t=head[a];t;t=e[t].nx)
#define Max(a,b) ((a)<(b)?(b):(a))
#define Min(a,b) ((a)<(b)?(a):(b))
#define midd register int mid=(l+r)>>1
#define TMP template < class ccf >
TMP inline ccf qr(ccf b){
char c=getchar();
int q=1;
ccf x=0;
while(c<48||c>57)
q=c==45?-1:q,c=getchar();
while(c>=48&&c<=57)
x=x*10+c-48,c=getchar();
return q==-1?-x:x;
}
const int maxn=155;
struct AC{
int fail;
int son[27];
int cnt;
inline int& operator [](int x){
return son[x];
}
inline int& operator [](char x){
return son[x-'a'+1];
}
}ac[maxn*70];
string x[maxn];
int toac[maxn];
int acnt[maxn];
int macnt[maxn];
int act;
int prcnt;
int n;
inline int build(string p,int len){
register int now=0;
RP(t,0,len-1){
if(!ac[now][p[t]])
ac[now][p[t]]=++act;
now=ac[now][p[t]];
}
if(!ac[now].cnt)
ac[now].cnt=++prcnt;
return ac[now].cnt;
}
queue < int > q;
inline void gen(){
RP(t,1,26){
if(ac[0][t])
q.push(ac[0][t]);
}
while(!q.empty()){
register int now=q.front();
q.pop();
RP(t,1,26){
if(ac[now][t])
ac[ac[now][t]].fail=ac[ac[now].fail][t],q.push(ac[now][t]);
else
ac[now][t]=ac[ac[now].fail][t];
}
}
}
inline void match(string p,int len){
register int now=0;
RP(t,0,len-1){
now=ac[now][p[t]];
for(register int i=now;i;i=ac[i].fail){
if(ac[i].cnt)
macnt[ac[i].cnt]++;
}
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("in.in","r",stdin);
freopen("out.out","w",stdout);
#endif
while( (n=qr(1)) ){
memset(ac,0,sizeof ac);
memset(macnt,0,sizeof macnt);
act=prcnt=0;
RP(t,1,n){
cin>>x[t];
toac[t]=build(x[t],x[t].length());
}
gen();
cin>>x[0];
match(x[0],x[0].length());
register int ans=0;
RP(t,1,prcnt)
ans=Max(ans,macnt[t]);
cout<<ans<<endl;
RP(t,1,n)
if(macnt[toac[t]]==ans)
cout<<x[t]<<endl;
}
return 0;
}