[BZOJ1212][HNOI2004]L语言
sol
设\(f_i\)表示文章的前\(i\)个字符是否可以被理解。每次匹配要暴跳\(fail\)到根,转移就是\(f_i|=f_{i-len}\),其中\(len\)是某个可以匹配的模式串的串长。
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N = 100005;
int n,m,ch[26][N],fail[N],dep[N],tot,len,f[N*10];
char s[N*10];
queue<int>Q;
void Insert()
{
scanf("%s",s);len=strlen(s);
int x=0;
for (int i=0;i<len;i++)
{
if (!ch[s[i]-'a'][x]) ch[s[i]-'a'][x]=++tot;
x=ch[s[i]-'a'][x];
}
dep[x]=len;
}
void Get_Fail()
{
for (int i=0;i<26;i++) if (ch[i][0]) Q.push(ch[i][0]);
while (!Q.empty())
{
int u=Q.front();Q.pop();
for (int i=0;i<26;i++)
if (ch[i][u]) fail[ch[i][u]]=ch[i][fail[u]],Q.push(ch[i][u]);
else ch[i][u]=ch[i][fail[u]];
}
}
void Query()
{
scanf("%s",s+1);len=strlen(s+1);
memset(f,0,sizeof(f));f[0]=1;
for (int i=1,x=0;i<=len;i++)
{
x=ch[s[i]-'a'][x];
for (int t=x;t;t=fail[t])
f[i]|=f[i-dep[t]];
}
for (int i=len;i>=0;i--) if (f[i]) return (void)printf("%d\n",i);
}
int main()
{
scanf("%d %d",&n,&m);
for (int i=1;i<=n;i++) Insert();
Get_Fail();
for (int i=1;i<=m;i++) Query();
return 0;
}