传送门
思路:
对单词建出
a
c
ac
ac自动机。
然后每次用文章去匹配的时候我们暴力枚举当前点在
f
a
i
l
fail
fail树上的所有祖先看是否有已经可以匹配的即可。
代码:
#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int rlen=1<<18|1;
inline char gc(){
static char buf[rlen],*ib,*ob;
(ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
return ib==ob?-1:*ib++;
}
inline int read(){
int ans=0;
char ch=gc();
while(!isdigit(ch))ch=gc();
while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
return ans;
}
inline int Read(char*s){
int top=0;
char ch=gc();
while(!isalpha(ch))ch=gc();
while(isalpha(ch))s[++top]=ch,ch=gc();
return top;
}
typedef long long ll;
int n,m;
char s[20];
bool ed[210];
char qry[1200005];
namespace acam{
int son[210][26],fail[210],tot,dep[210];
inline int newnode(){return fail[++tot]=0,ed[tot]=0,memset(son[tot],0,sizeof(son[tot])),tot;}
inline void insert(char*s,int up){
ri p=0;
for(ri i=1,x;i<=up;++i){
if(!son[p][x=s[i]-'a'])son[p][x]=newnode();
dep[son[p][x]]=dep[p]+1;
p=son[p][x];
}
ed[p]=1;
}
inline void getfail(){
static int q[210],hd,tl;
hd=1,tl=0;
for(ri i=0;i<26;++i)if(son[0][i])q[++tl]=son[0][i];
while(hd<=tl){
int p=q[hd++];
for(ri i=0;i<26;++i){
if(!son[p][i]){son[p][i]=son[fail[p]][i];continue;}
fail[q[++tl]=son[p][i]]=son[fail[p]][i];
}
}
}
inline void query(char*s,int up){
static bool ok[1000005];
int ans=0;
ok[0]=1;
for(ri i=1,p=0;i<=up;++i){
ok[i]=0;
p=son[p][s[i]-'a'];
for(ri j=p;j;j=fail[j])if(ed[j]&&ok[i-dep[j]]){ok[i]=1;break;};
}
for(ri i=up;~i;--i)if(ok[i]){cout<<i<<'\n';return;}
}
}
int main(){
n=read(),m=read();
for(ri len,i=1;i<=n;++i){
len=Read(s);
acam::insert(s,len);
}
acam::getfail();
for(ri i=1,len;i<=m;++i){
len=Read(qry);
acam::query(qry,len);
}
return 0;
}