题目
http://www.lydsy.com/JudgeOnline/problem.php?id=1212
题解
其实很水啦
把字典建成AC自动机
每个串在上面跑,用can[i]表示前缀i是否能被解释,每次move一个字符,如果当前字符所处的位置正好有tail标记,就顺着fail往上找,其实就相当于枚举最后一个单词,假设枚举的这个单词的长度为L,那么如果can[i-L]为true的话,can[i]就也为true,如果找不到一个L使得can[i-L]为true,can[i]就是false
代码
//AC自动机
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cstring>
using namespace std;
int trie[300][30], n, m, tail[300], fail[300], tot=1, ans, can[1500000], deep[300];
char s[1500000];
queue<int> q;
void insert()
{
char *p=s;
int pos;
for(pos=1;*p;p++)
pos = trie[pos][*p-97] ? trie[pos][*p-97] : trie[pos][*p-97]=++tot;
tail[pos]++;
}
void acabuild()
{
int u, f, i;
q.push(1);
while(!q.empty())
{
u=q.front(),q.pop();
for(i=0;i<26;i++)
{
if(trie[u][i])
{
for(f=fail[u];f and !trie[f][i];f=fail[f]);
if(f)fail[trie[u][i]]=trie[f][i];
else fail[trie[u][i]]=1;
q.push(trie[u][i]);
deep[trie[u][i]]=deep[u]+1;
}
}
}
}
void solve()
{
int i, j, pos, x;
for(i=1;i<=m;i++)
{
scanf("%s",s+1);
ans=0;
pos=1;
memset(can,0,sizeof(can));
can[0]=1;
for(j=1;s[j];j++)
{
for(;pos and !trie[pos][s[j]-97];pos=fail[pos]);
pos = pos ? trie[pos][s[j]-97] : 1;
if(fail[pos])
{
for(x=pos;x>1 and !can[j];x=fail[x])
if(tail[x] and can[j-deep[x]])can[j]=1;
if(can[j])ans=j;
}
}
printf("%d\n",ans);
}
}
void init()
{
int i;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)scanf("%s",s),insert();
for(i=2;i<=n;i++)fail[i]=1;
acabuild();
}
int main()
{
init();
solve();
return 0;
}