一、sam的性質:
sam是個狀態機。乙個起點,若干終點。原串的所有子串和從sam起點開始的所有路徑一一對應,不重不漏。所以終點就是包含字尾的點。
每個點包含若干子串,每個子串都一一對應一條從起點到該點的路徑。且這些子串一定是裡面最長子串的連續字尾。
sam問題中經常考慮兩種邊:
(1) 普通邊,類似於trie。表示在某個狀態所表示的所有子串的後面新增乙個字元。
(2) link、father。表示將某個狀態所表示的最短子串的首字母刪除。這類邊構成一棵樹。
二、sam的構造思路
endpos(s):子串s所有出現的位置(尾字母下標)集合。sam中的每個狀態都一一對應乙個endpos的等價類。
endpos的性質:
(1) 令 s1,s2 為 s 的兩個子串 ,不妨設 |s1|≤|s2| (我們用 |s| 表示 s 的長度 ,此處等價於 s1 不長於 s2 )。則 s1 是 s2 的字尾當且僅當 endpos(s1)⊇endpos(s2) ,s1 不是 s2 的字尾當且僅當 endpos(s1)∩endpos(s2)=∅ 。
(2) 兩個不同子串的endpos,要麼有包含關係,要麼沒有交集。
(3) 兩個子串的endpos相同,那麼短串為長串的字尾。
(4) 對於乙個狀態 st ,以及任意的 longest(st) 的字尾 s ,如果 s 的長度滿足:|shortest(st)|≤|s|≤|longsest(st)| ,那麼 s∈substrings(st) 。
sam的應用
1可以將其看作一字串的hash表,用於查詢
2求該字串的不同子串的數量
//每乙個點包括的字串集合
3求某一子串在該改串的出現次數->劃分endpos,遞迴的找
給定乙個長度為 n
'>
n 的只包含小寫字母的字串 s
'>
s。對於所有 s
'>s
的出現次數不為 1
'>1
的子串,設其 val
ue'>value
值為該子串出現的次數 ×
'>
× 該子串的長度。
請計算,val
ue'>value
的最大值是多少。
輸入格式
共一行,包含乙個由 n
'>n
個小寫字母構成的字串。
輸出格式
共一行,輸出乙個整數,表示答案。
資料範圍1≤
n≤106
'>1≤n≤1e6
保證至少存在乙個子串出現次數大於 1
'>1
1。輸入樣例:
aabab
輸出樣例:4
#include #include#include
using
namespace
std;
typedef
long
long
ll;const
int n = 2000010
;int tot = 1, last = 1
;struct
node
node[n];
char
str[n];
ll f[n], ans;
inth[n], e[n], ne[n], idx;
void extend(int
c) }
}void add(int a, int
b)void dfs(int
u)
if (f[u] > 1) ans = max(ans, f[u] *node[u].len);
}int
main()
字尾自動機
基礎知識 step i 表示的是字串i在原字串中的位置。pareint i 表示root到parent i 的子串是root到i的最長字尾。字尾自動機遍歷可以得到原字串的所有子串。特殊技巧 一 字尾自動機的不同子串數有兩種求法 1.ans step i step parent i 1 i cnt 2...
字尾自動機
常用於處理字串問題,可以高效解決許多字串問題。有點像將乙個字串的所有字尾都建在乙個ac自動機上,但不同的是字尾自動機的節點數最多為2 n,因為它只記錄需要記錄的點,一些沒有記錄東西的點可以視為與下面有價值的節點並在一起,這樣大大降低了時間複雜度和空間複雜度。對於每乙個節點記錄它的後面加上每個字元後字...
字尾自動機
基礎學習 簡潔明瞭的講解 總狀態數不超過2n 12n 1 2n 1 包括初始狀態 統計每個end po sendpos endpos 等價類出現位置數量時,要按長度從長到短的計算cnt cntcn t。那為什麼一定要從長到短呢?比如回文自動機就直接是按照節點編號從大到小計算cnt cntcn t 罪...