您的位置:首页 > 其它

BZOJ2946: [Poi2000]公共串

2016-12-30 18:11 274 查看
第一次写后缀自动机,好激动,参照了Po姐的写法,这道题我们只需将第一个串建立后缀自动机,然后其他的串在上面跑就可以了,找到一个最长的n个串都经过的子串就可以了(后缀自动机真快啊)

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cstring>
#include<string>
#include<iostream>
#include<iomanip>
#include<algorithm>
using namespace std;
struct sam
{
sam *son[26],*parent;
int max_len;
int min_len[6];
bool v;
sam(int _=0):max_len(_),parent(0x0),v(false)
{
memset(min_len,0,sizeof(min_len));
memset(son,0,sizeof(son));
}
}*root=new sam,*last=root;
void my_insert(int x)
{
sam *p=last;
sam *np=new sam(p->max_len+1);
while(p && !p->son[x])
{
p->son[x]=np;
p=p->parent;
}
if(!p) np->parent=root;
else
{
sam *q=p->son[x];
if(p->max_len+1==q->max_len) np->parent=q;
else
{
sam *nq=new sam(p->max_len+1);
nq->parent=q->parent;

memcpy(nq->son,q->son,sizeof q->son);
q->parent=nq;np->parent=nq;
while(p && p->son[x]==q)
{
p->son[x]=nq;
p=p->parent;
}
nq->min_len[1]=nq->max_len;
}
}
last=np;
np->min_len[1]=np->max_len;
}
char s[2020];
int ans=0;
int n;
void dfs(sam *o)
{
o->v=true;
int minn=2147483647;
for(int i=1;i<=n;i++)
if(o->min_len[i]<minn) minn=o->min_len[i];
ans=max(ans,minn);
for(int i=0;i<26;i++)
{
if(o->son[i] && !o->son[i]->v) dfs(o->son[i]);
}
}
int main()
{
scanf("%d",&n);
scanf("%s",s+1);
for(int i=1;s[i];i++) my_insert(s[i]-'a');
for(int i=2;i<=n;i++)
{
scanf("%s",s+1);
sam *o=root;
int len=0;
for(int j=1;s[j];j++)
{
while(o!=root && !o->son[s[j]-'a'])
{
o=o->parent;
len=o->max_len;
}
if(o->son[s[j]-'a'])
{
o=o->son[s[j]-'a'];
len++;
}
for(sam *temp=o;temp;temp=temp->parent) temp->min_len[i]=max(temp->min_len[i],min(len,temp->max_len));
}
}
dfs(root);
cout<<ans;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  后缀自动机 BZOJ