您的位置:首页 > 其它

bzoj 1212: [HNOI2004]L语言 AC自动机+状压

2017-02-28 16:55 369 查看
  为什么这道题网上所有题解写的都是N*Len的trie树的暴力啊,4E的复杂度。。。

  为什么暴力还跑这么快啊TAT。。

  有一个O(Len)的做法就是先把AC自动机建出来,因为每个字典串的长度很小,所以我们可以用fail树状压一发,每个节点记录一个值ss,表示这个点向前(1~10)的长度的串是不是一个字典串,这个东西延fail树递推就行了。

  然后每次把每个串放AC自动机上走,同时记录一个值T表示(s(1,i-11)~s(1-(i-1)))这些串能否成为答案,如果如果T&ss!=0那么i这个点就可以成为答案。

  

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int n,m;
char s[1500000];
int ch[1005][26];int cnt;int v[10005];
int fail[1005];int len[1005];
void insert()
{
int ln=strlen(s);int now=0;
for(int i=0;i<ln;i++)
{
int c=s[i]-'a';
if(ch[now][c])
{
now=ch[now][c];
}
else
{
ch[now][c]=++cnt;
len[cnt]=len[now]+1;
now=ch[now][c];
}
}
v[now]=1;
}
queue<int>q;
unsigned int ss[1005];
void build()
{
for(int i=0;i<26;i++)if(ch[0][i])q.push(ch[0][i]);
while(!q.empty())
{
int tmp=q.front();q.pop();
for(int i=0;i<26;i++)
{
if(ch[tmp][i])
{
q.push(ch[tmp][i]);
fail[ch[tmp][i]]=ch[fail[tmp]][i];
}
else
{
ch[tmp][i]=ch[fail[tmp]][i];
}
}
if(v[tmp])ss[tmp]=(ss[fail[tmp]]^(1<<(len[tmp]-1)));
else ss[tmp]=ss[fail[tmp]];
}
return ;
}
unsigned int tmp;
void solve()
{
int ans=0;
unsigned int ssr=1;
int ln=strlen(s+1);
int now=0;
for(int i=1;i<=ln;i++)
{
int c=s[i]-'a';
now=ch[now][c];
tmp=ssr;
ssr<<=1;
if(tmp&ss[now])ans=max(ans,i),ssr^=1;
}
printf("%d\n",ans);
return ;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%s",s);
insert();
}
build();
for(int i=1;i<=m;i++)
{
scanf("%s",s+1);
solve();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: