後綴自動機經典操做

看了幾天的後綴自動機,感受這玩意兒確實比較神奇。可是感受本身確定講不明白,就簡單的來寫寫心得和應用吧html

性質

一、每一個狀態$s$表明的長度區間爲$(len[fa[s]],len[s])$算法

也就是說$min(s) = max(s) + 1$post

 

二、每一個狀態$s$表明的全部串在原串中的出現次數及出現位置右端點相同。url

這也是後綴自動機可以壓縮狀態的緣由,就是把不少相同的串壓縮到一個節點中spa

 

三、在parent樹中,對於狀態$s$,$fa[s]$所代表的狀態是$s$所表明狀態的後綴htm

 

四、在parent樹中,每一個狀態的$right$集合是它父節點$right$集合的子集blog

由性質$3$很容易獲得$fa[s]$所表明的狀態是$s$所表明狀態的後綴,那麼$fa[x]$所表明的子串的出現位置必定比$s$表明子串的出現位置多排序

 

五、對轉移邊造成的DAG拓撲排序後,每一個節點對應的大小爲:以該節點爲起點的子串的數量(本質相同的子串算一個)字符串

 

六、對$fa$邊造成的樹拓撲排序後,每一個節點對應的大小爲該節點對應$right$集合的大小get

$fa[s]$表示的是$s$的前綴,那麼$s$出現的地方$fa[s]$也必定出現

 

經典應用

求兩個串的最長公共子串

首先把第一個串的SAM建出來,

枚舉第二個串,同時沿着轉移邊進行匹配,若匹配失敗,那麼就沿着$fa$邊向上走,

匹配的同時記錄一下$max$

SPOJ1811 LCS 

求多個串的最長公共子串

網上的作法基本都是對第一個串建SAM,而後枚舉其餘的串,在這個串上匹配。

可是貌似要考慮不少東西??

這裏我將一個比較naive可是不會TLE的作法。

最終的答案必定出如今第一個串中,因此能夠把第$2-N$個串的SAM建出來

而後枚舉第一個串的每一位,在其他的SAM中匹配。

雖然聽着嚇人,可是代碼十分好寫

BZOJ2946 [Poi2000]公共串

求第$k$小子串

咱們能夠經過對轉移邊$dfs$而求出以該節點爲起點的子串的大小

開始時從$root$開始走,每次優先選擇字典序小的轉移邊,

若該出邊對應的大小$<k$,說明答案不在該出邊所對應的字符串中,令$k$減去該節點的大小,繼續匹配

若該出邊對於的大小$>=k$,說明答案在該出邊中,那麼沿着該出邊繼續走

 

注意在求第$k$小子串的時候要考慮本質相同的子串是否重複統計的問題

若是要重複統計,則加上$right$集合的大小就能夠了

 

不重複統計SPOJ7258 SUBLEX

重複統計BZOJ3998: [TJOI2015]弦論

 

字符串最小表示法

最小表示法的定義:

字符串$S$的最小表示法爲,對於任意的$i \in [1, |S|]$,把$[1,i]$對應的字符串剪切到$S$尾所造成的字符串中,字典序最小的一個

 

字符串的最小表示有它本身的算法,能夠參考這裏

固然後綴自動機也是能夠搞的,咱們首先把字符串複製一遍,扔到SAM裏,

而後從根節點出發貪心的走較小的出邊,同時輸出每一次通過的字符,當達到$N$次時中止。

 

可是我仍是建議你們學一下最小表示法的標準算法, 由於後綴自動機須要$4*|S|*siz$的空間($siz$表示字符集),很容易被卡掉

POJ1509 Glass Beads

 

求本質不一樣的串的數量

考慮到每一個狀態表示的子串是兩兩不一樣的,

根據性質1每一個狀態$s$表明的長度區間爲$(len[fa[s]],len[s]]$

而後對全部節點求個和就好,答案爲$\sum_{t} len[t] - len[fa[t]]$

相關文章
相關標籤/搜索