看了幾天的後綴自動機,感受這玩意兒確實比較神奇。可是感受本身確定講不明白,就簡單的來寫寫心得和應用吧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$
網上的作法基本都是對第一個串建SAM,而後枚舉其餘的串,在這個串上匹配。
可是貌似要考慮不少東西??
這裏我將一個比較naive可是不會TLE的作法。
最終的答案必定出如今第一個串中,因此能夠把第$2-N$個串的SAM建出來
而後枚舉第一個串的每一位,在其他的SAM中匹配。
雖然聽着嚇人,可是代碼十分好寫
咱們能夠經過對轉移邊$dfs$而求出以該節點爲起點的子串的大小
開始時從$root$開始走,每次優先選擇字典序小的轉移邊,
若該出邊對應的大小$<k$,說明答案不在該出邊所對應的字符串中,令$k$減去該節點的大小,繼續匹配
若該出邊對於的大小$>=k$,說明答案在該出邊中,那麼沿着該出邊繼續走
注意在求第$k$小子串的時候要考慮本質相同的子串是否重複統計的問題
若是要重複統計,則加上$right$集合的大小就能夠了
最小表示法的定義:
字符串$S$的最小表示法爲,對於任意的$i \in [1, |S|]$,把$[1,i]$對應的字符串剪切到$S$尾所造成的字符串中,字典序最小的一個
字符串的最小表示有它本身的算法,能夠參考這裏
固然後綴自動機也是能夠搞的,咱們首先把字符串複製一遍,扔到SAM裏,
而後從根節點出發貪心的走較小的出邊,同時輸出每一次通過的字符,當達到$N$次時中止。
可是我仍是建議你們學一下最小表示法的標準算法, 由於後綴自動機須要$4*|S|*siz$的空間($siz$表示字符集),很容易被卡掉
考慮到每一個狀態表示的子串是兩兩不一樣的,
根據性質1每一個狀態$s$表明的長度區間爲$(len[fa[s]],len[s]]$
而後對全部節點求個和就好,答案爲$\sum_{t} len[t] - len[fa[t]]$