[bzoj1212][HNOI2004]L语言_AC自动机_动态规划

时间:2025-04-17 19:34:37

L语言 bzoj-1212 HNOI-2004

题目大意:给你一个n个单词的集合,然后给你m条字符串。问每条字符串可以被理解的最长前缀。被理解当且仅当存在一种分割使得每一段都是集合里的元素。

注释:$1\le n,m\le 20$,长度不超过1M

想法:做了上一道,感觉这是个大水题... ...,我们将那个单词集合建立一个AC自动机,然后将每一个询问的字符串仍在字符串上跑,用bool型的dp。

dp[i]表示当前字符串前i位是否能被理解。

转移:如果j+1到i这段能被理解,那么dp[i]|=dp[j];

最后,附上丑陋的代码... ...

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 2000010
using namespace std;
char s[N];
int a[300][26];
bool end[300];
int n,m,cnt,fail[300],f[N];
void build(char *s)
{
int now=0;
int len=strlen(s);
for(int i=0;i<len;i++)
{
if(!a[now][s[i]-'a'])
{
a[now][s[i]-'a']=++cnt;
}
now=a[now][s[i]-'a'];
}
end[now]=true;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%s",s);
build(s);
}
while(m--)
{
scanf("%s",s);
int l=strlen(s);
memset(f,0,sizeof f);
f[0]=1;
for(int i=0;i<l;i++)
{
if(f[i])
{
int now=0;
for(int j=i;a[now][s[j]-'a'];j++)
{
now=a[now][s[j]-'a'];
if(end[now])
{
f[j+1]|=f[i];
}
}
}
}
for(int i=l;~i;i--)
{
if(!f[i]) continue;
printf("%d\n",i);
break;
}
}
}

小结:ac自动接其实可以当Trie使.. ...虽然我写这东西是Trie图..