SPOJ LCS2 字尾自動機

2022-03-28 17:20:26 字數 1808 閱讀 1737

題目傳送門

題目大意:還是求字串的最長公共子串,只不過這次是n個串。

思路:先把第乙個串丟到sam裡面去,然後每乙個串都和前面那個串做一次最長公共子串的匹配。我們現在把sam裡面的其中乙個狀態記做$p$,這個$p$其實就代表了$right$集合相同的所有子串,我們要記錄每乙個狀態下的最大匹配長度(通俗的理解,有乙個子串是p,所有串的公共子串就是這個p)。然後把所有匹配串和原串都匹配一遍,每個$p$模式下取最小值。

但是這裡會有乙個問題,假設我們此時有$aaaaaab$,$aaaaaab$,$cccaaab$這樣三個串,按照如上方式匹配,會發現$aaab$這個答案串對應的p會被我們忽略掉(在拿第二個串和第乙個串匹配的時候,直接一路到底了,$aaab$這個串的p根本就沒有更新),我們遺漏了答案,原因是我們在更新$aaaaaab$的時候,並沒有更新$aaab$。

那要怎麼辦呢?我們會發現,$aaab$是$aaaaaab$的父串之一,所以,mxf[i

]'>i可以更新mxf[i

.par

ent]

'>[i.parent],f[

i]'>f[i

.par

ent]

'>為了使得更快的更新且不重複,我們先處理所有長度比較長的p,然後每個p都更新長度短一些的父串。f[

i]'>f[i

.par

ent]

'>這裡用的是拓撲排序,看**會更容易理解一些。要區別好拓撲排序的$i$是從1開始的還是從$tot$開始的。f[

i]'>f[i

.par

ent]

'>ps:強烈譴責網上幾個**根本ac不了的部落格,有幾個甚至第三組就wa了,我自動機模板寫錯的時候都過了九組資料。而且這樣的部落格還不止乙個。。

#include#define clr(a,b) memset(a,b,sizeof(a))

using

namespace

std;

typedef

long

long

ll;const

int inf=0x3f3f3f3f

;const

int maxn=100010

;char

s[maxn];

int len[maxn<<1],ch[maxn<<1][27],fa[maxn<<1],tot=1,root=1,last=1

,siz;

void extend(int

x)

if(!pre)fa[now]=root;

else}}

}int mn[maxn<<1],mx[maxn<<1],c[maxn<<1],a[maxn<<1

];int

main()

for(int i=1;i<=tot;i++)c[len[i]]++;

for(int i=1;i<=tot;i++)c[i]+=c[i-1

];

for(int i=tot;i>0;i--)a[c[len[i]]--]=i;

for(int i=tot;i>0;i--)mn[i]=len[i];

while(scanf("

%s",s)!=eof)

else

else

}mx[cur]=max(mx[cur],maxx);

}for(int i=tot;i>0;i--)

for(int i=tot;i>0;i--)mn[i]=min(mn[i],mx[i]);

}int ans=0

;

for(int i=tot;i>0;i--)

cout

}

SPOJ LCS2 字尾自動機

題意 求多個串的lcs 思路 跟上題一樣的東西 只不過多加乙個臨時的dp陣列來儲存所有的狀態的最小值 然後求所有子串的最大值就好了 include include include include include include include include include include incl...

SPOJ LCS2 字尾自動機

給多個字串,問最長公共子串。最長公共子串用字尾自動機還是很方便的,首先的話,有乙個非常重要的字尾自動機性質一定要明確,字尾自動機乙個點的par一定是這個點代表的所有字元子串的公共字尾。了解了這一點,我們便可以構造字尾自動機,然後進行匹配。在匹配的過程中,如果可以成功轉移,直接轉移並且把記錄的長度 就...

spoj LCS 字尾自動機

琦不會字尾自動機 是以前太浪了 所以所有東西都留到了noi前來學 馬上狗牌退役了tat 心塞qwq 題目大意 給出兩個串a,b,求a b的最長公共子串 對a建字尾自動機,然後用b去匹配,若能匹配上就轉移到兒子,否則沿著parent樹向上跳 include include include includ...