【再談字尾自動機(入門)】[SPOJLCS2]Longest Common Substring II
阿新 • • 發佈:2019-02-12
題目大意
給出
分析
關於字尾自動機
複習過程中再看字尾自動機,把許多初學的時候沒弄懂的問題解決了。
首先要明確字尾自動機的每個節點所表示的是一個終點等價類,從根節點走到葉子節點就對應一個字尾,
字尾邊所指向的節點所對應的終點等價類的終點包含當前節點的終點等價類對應的終點。
在構建的過程中
q−>len≠p−>len+1 ,說明由p 轉移到q 並不是q 點所對應的最長的字串但這卻是能夠增加這個終點的最長的字串,q 所對應的長於該長度的字串都不能增加這個終點,,所以我們新建一個節點nq ,將q 的資訊複製給他(len,fail,ch) ,nq→len=p→len+1,q→fial=nq,np→fial=nq ,並且沿著字尾邊走,將所有有字元c 轉移且轉移到q 的轉移重定向至nq 。
為什麼ch 也要複製?
因為這個節點對應的字串加上轉移的邊所對應的字元形成的字串的終點和這個節點的終點的沒有關係,所以要保證這個節點的兒子節點所對應的字串不變。q−>len=p−>len+1 ,則np→fial=q
這道題
每個節點儲存兩個值:當前字串能夠匹配這個節點對應的字串的最大長度
然後,每次匹配完之後要沿著字尾邊更新
程式碼
#include<cstdio>
#include<cstring>
#include<algorithm>
#define INF 0x7fffffff
#define MAXN 100000
using namespace std;
void Read(int &x){
char c;
while(c=getchar(),c!=EOF)
if(c>='0'&&c<='9'){
x=c-'0';
while(c=getchar(),c>='0'&&c<='9')
x=x*10+c-'0';
ungetc(c,stdin);
return;
}
}
struct node{
int len,mx,nmx;
node *ch[26],*fail;
}tree[MAXN*2+10],*tcnt=tree,*root=tcnt,*l=tcnt,*r[MAXN*2+10];
char s[MAXN+10];
int ans,b[MAXN+10];
void insert(char c){
c-='a';
node *p=l,*np=++tcnt,*q,*nq;
l=np;
np->len=p->len+1;
while(p&&!p->ch[c])
p->ch[c]=np,p=p->fail;
if(!p)
np->fail=root;
else{
q=p->ch[c];
if(q->len==p->len+1)
np->fail=q;
else{
nq=++tcnt;
*nq=*q;
nq->len=p->len+1;
q->fail=nq;
np->fail=nq;
while(p&&p->ch[c]==q)
p->ch[c]=nq,p=p->fail;
}
}
}
void read(){
scanf("%s",s);
for(int i=0;s[i];i++)
insert(s[i]);
}
void solve(){
int i,len,tot;
node *p;
for(p=tree;p<=tcnt;p++){
p->mx=p->len,p->nmx=0;
b[p->len]++;
}
for(i=1;s[i-1];i++)
b[i]+=b[i-1];
for(p=tree;p<=tcnt;p++)
r[--b[p->len]]=p;
tot=tcnt-tree;
while(~scanf("%s",s)){
p=root;
len=0;
for(i=0;s[i];i++){
s[i]-='a';
if(p->ch[s[i]]){
p=p->ch[s[i]];
p->nmx=max(p->nmx,++len);
}
else{
while(p&&!p->ch[s[i]])
p=p->fail;
if(!p)
p=root,len=0;
else{
len=p->len+1;
p=p->ch[s[i]];
p->nmx=max(p->nmx,len);
}
}
}
for(i=tot;i;i--){
r[i]->fail->nmx=max(r[i]->nmx,r[i]->fail->nmx);//不用和r[i]->len進行比較,因為不會影響更新r[i]->mx
r[i]->mx=min(r[i]->mx,r[i]->nmx);
r[i]->nmx=0;
}
}
for(p=tree;p<=tcnt;p++)
ans=max(ans,p->mx);
}
int main()
{
read();
solve();
printf("%d\n",ans);
}