题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1212
把给定的单词建成一个AC自动机,然后把给的文章在上面跑即可。
f[i]表示能不能匹配到第i个字符,当第i个字符在AC自动机上走到了x节点,如果x是一个danger节点那么就一直跳x的fail指针,如果路径上有danger节点,f[i]|=f[i-w[x]] (其中w[x]表示:如果x为终止节点那么这个字符串的长度是多少)
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
const int M=1000005;
const int N=1005;
int n,m,f[M],e[N][30],fail[N],cnt=1,w[N];
char s[M],ch[30];
bool danger[N];
void insert()
{
scanf("%s",ch+1);
int x=1;
for(int i=1;ch[i];i++)
{
int o=ch[i]-'a'+1;
if(!e[x][o]) e[x][o]=++cnt;
x=e[x][o];
}
w[x]=strlen(ch+1);
danger[x]=true;
}
queue<int>Q;
void build()
{
for(int i=1;i<=26;i++) e[0][i]=1;
fail[1]=0;
Q.push(1);
while(!Q.empty())
{
int x=Q.front();
Q.pop();
for(int i=1;i<=26;i++)
{
int v=e[x][i];
if(v) fail[v]=e[fail[x]][i],Q.push(v);
else e[x][i]=e[fail[x]][i];
}
danger[x]|=danger[fail[x]];
}
}
void match()
{
int x=1;
for(int i=1;s[i];i++)
{
int o=s[i]-'a'+1;
x=e[x][o];
if(danger[x])
{
int y=x;
while(y)
{
if(w[y]) f[i]|=f[i-w[y]];
y=fail[y];
}
}
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) insert();
build();
while(m--)
{
scanf("%s",s+1);
int len=strlen(s+1);
memset(f,0,sizeof(f));
f[0]=1;
match();
for(int i=len;i>=0;i--)
if(f[i]) {printf("%d\n",i);break;}
}
}