●POJ 2774 Long Long Message

时间:2023-03-08 19:55:53

题链:

http://poj.org/problem?id=2774
题解:

后缀自动机
使用后缀自动机匹配,思路如下:
即如果当前的x字符匹配失败了,就可以从当前已经匹配的串的后缀去继续匹配。
然后不难发现,对于失配的状态s的parent[s]恰好是可能能够继续匹配x且Right集合是最小的包含s的Right集合(即允许的合法长度除了s外是最长的)的状态。
所以就沿着parent指针向上跳,直到trans[*][x]存在或者到了0号节点。

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#define MAXN 250005
using namespace std;
struct SAM{
int size,last;
int maxs[MAXN*5],trans[MAXN*5][26],parent[MAXN*5];
int Newnode(int a,int b){
maxs[size]=a;
memcpy(trans[size],trans[b],sizeof(trans[b]));
return size++;
}
void Extend(int x){
static int p,np,q,nq;
p=last; last=np=Newnode(maxs[p]+1,0);
for(;p&&!trans[p][x];p=parent[p]) trans[p][x]=np;
if(!p) parent[np]=1;
else{
q=trans[p][x];
if(maxs[p]+1!=maxs[q]){
nq=Newnode(maxs[p]+1,q);
parent[nq]=parent[q];
parent[q]=parent[np]=nq;
for(;p&&trans[p][x]==q;p=parent[p]) trans[p][x]=nq;
}
else parent[np]=q;
}
}
void Build(char *S){
memset(trans[0],0,sizeof(trans[0]));
size=1; last=Newnode(0,0);
for(int i=0;S[i];i++) Extend(S[i]-'a');
}
int Match(char *T){
int p=1,i=0,ans=0,now=0,len=strlen(T);
while(i<len){
if(p&&!trans[p][T[i]-'a']){
ans=max(ans,min(now,maxs[p]));
p=parent[p]; now=maxs[p];
}
else if(p) now++,p=trans[p][T[i]-'a'],i++;
else i++,p=1;
}
return max(ans,min(now,maxs[p]));
}
}SUF;
int main(){
char S[MAXN];
scanf("%s",S);
SUF.Build(S);
scanf("%s",S);
int ans=SUF.Match(S);
printf("%d\n",ans);
return 0;
}