一道大水题
这个题很水啊,我交了两次就过了(错的那次放在最底下,供大家参考,吸取教训)。
用f[i]表示到第i位能否被识别,转移f[i]|=f[i-len],其中len是找到新单词的长度,然后就很明显的AC自动机。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int n,m,ans;
char s[1048578];
bool f[1048578];
class Trie
{
public:
int flg;
Trie *f,*lst,*nxt[26];
Trie()
{
for(int i=0;i<26;++i)
nxt[i]=NULL;
f=lst=NULL;
flg=0;
}
}root,*now;
inline int read()
{
char ch=getchar();int ret=0,f=1;
while(ch>'9'||ch<'0'){if(ch=='-')f=-f;ch=getchar();}
while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
return ret*f;
}
void ACA()
{
queue<Trie*>que;
for(int i=0;i<26;++i)
{
if(root.nxt[i])
{
que.push(root.nxt[i]);
root.nxt[i]->f=&root;
}
}
while(!que.empty())
{
Trie *hed=que.front();
que.pop();
for(int i=0;i<26;++i)
{
if(!hed->nxt[i])
continue;
que.push(hed->nxt[i]);
Trie *u=hed->f;
while(u&&!u->nxt[i])
u=u->f;
if(!u)
hed->nxt[i]->f=&root;
else
{
hed->nxt[i]->f=u->nxt[i];
hed->nxt[i]->lst=u->nxt[i]->flg?u->nxt[i]:u->nxt[i]->lst;
}
if(!hed->nxt[i]->f)
hed->nxt[i]->f=&root;
}
}
}
void update(Trie *now,int j)
{
if(now->flg)
f[j]|=f[j-now->flg];
if(now->lst)
update(now->lst,j);
}
void find()
{
f[0]=1;
ans=0;
now=&root;
for(int j=1;s[j];++j)
{
f[j]=0;
int i=s[j]-'a';
while(now&&!now->nxt[i])
now=now->f;
if(!now)
now=&root;
else
{
now=now->nxt[i];
if(now->flg)
update(now,j);
if(now->lst)
update(now->lst,j);
}
if(f[j])
ans=j;
}
}
int main()
{
freopen("test.in","r",stdin);
freopen("test.out","w",stdout);
n=read(),m=read();
for(int i=1,j;i<=n;++i)
{
scanf("%s",s);
now=&root;
for(j=0;s[j];++j)
{
if(!now->nxt[s[j]-'a'])
now->nxt[s[j]-'a']=new Trie;
now=now->nxt[s[j]-'a'];
}
now->flg=j;
}
ACA();
for(int i=1;i<=m;++i)
{
scanf("%s",s+1);
find();
printf("%d\n",ans);
}
return 0;
}
接下来是错误的代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int n,m,ans;
char s[1048578];
bool f[1048578];
class Trie
{
public:
int flg;
Trie *f,*lst,*nxt[26];
Trie()
{
for(int i=0;i<26;++i)
nxt[i]=NULL;
f=lst=NULL;
flg=0;
}
}root,*now;
inline int read()
{
char ch=getchar();int ret=0,f=1;
while(ch>'9'||ch<'0'){if(ch=='-')f=-f;ch=getchar();}
while(ch>='0'&&ch<='9')ret=ret*1+ch-'0',ch=getchar();
return ret*f;
}
void ACA()
{
queue<Trie*>que;
for(int i=0;i<26;++i)
{
if(root.nxt[i])
{
que.push(root.nxt[i]);
root.nxt[i]->f=&root;
}
}
while(!que.empty())
{
Trie *hed=que.front();
que.pop();
for(int i=0;i<26;++i)
{
if(!hed->nxt[i])
continue;
que.push(hed->nxt[i]);
Trie *u=hed->f;
while(u&&!u->nxt[i])
u=u->f;
if(!u)
hed->nxt[i]->f=&root;
else
{
hed->nxt[i]->f=u->nxt[i];
hed->nxt[i]->lst=u->nxt[i]->flg?u->nxt[i]:u->nxt[i]->lst;
}
if(!hed->nxt[i]->f)
hed->nxt[i]->f=&root;
}
}
}
void update(Trie *now,int j)
{
if(now->flg)
f[j]|=f[j-now->flg];
if(now->lst)
update(now->lst,j);
}
void find()
{
f[0]=1;
ans=0;
now=&root;
for(int j=1;s[j];++j)
{
f[j]=0;
int i=s[j]-'a';
while(now&&!now->nxt[i])
now=now->f;
if(!now)
now=&root;
else
{
now=now->nxt[i];
if(now->flg)
update(now,j);
if(now->lst)
update(now->lst,j);
}
if(f[j])
ans=j;
}
}
int main()
{
freopen("test.in","r",stdin);
freopen("test.out","w",stdout);
n=read(),m=read();
for(int i=1,j;i<=n;++i)
{
scanf("%s",s);
now=&root;
for(j=0;s[j];++j)
{
if(!now->nxt[s[j]-'a'])
now->nxt[s[j]-'a']=new Trie;
now=now->nxt[s[j]-'a'];
}
now->flg=j;
}
ACA();
for(int i=1;i<=m;++i)
{
scanf("%s",s+1);
find();
printf("%d\n",ans);
}
return 0;
}
read函数里10打成了1
老套路
转载不用注明出处,真不会有人转的。