好文**
luogup3804
**:
/*view code定義.對給定字串s的字尾自動機是乙個最小化確定有限狀態自動機,它能夠接收字串s的所有字尾。
對給定字串s的字尾自動機是乙個最小化確定有限狀態自動機,它能夠接收字串s的所有字尾。
某一狀態t_0被稱作初始狀態,由它能夠到達其餘所有狀態。
自動機中的所有轉移——即有向邊——都被某種符號標記。從某一狀態出發的諸轉移必須擁有不同的標記。(另一方面,狀態轉移不能在任何字元上)。
乙個或多個狀態被標記為終止狀態。如果我們從初始狀態t_0經由任意路徑走到某一終止狀態,並順序寫出所有經過邊的標記,你得到的字串必然是s的某一字尾。
在符合上述諸條件的所有自動機中,字尾自動機有這最少的頂點數。(字尾自動機並不被要求擁有最少的邊數)
最簡性:它包含了所有s的子串的資訊。換言之,對於任意從初始狀態t_0出發的路徑,如果我們寫出所經過邊上的標記,形成的子串必須是s的子串。相應地,s的任意子串都對應一條從初始狀態t_0出發的路徑。
為了簡化說明,我們稱子串「匹配」了從初始狀態出發的路徑,如果該路徑上的邊標記組成了這一子串。相應地,我們稱任意路徑「匹配」某一子串,該子串由路徑中邊的標記組成。
字尾自動機的每個狀態都引領一條或多條從初始狀態出發的路徑。我們稱這個狀態有若干匹配這些路徑的方法。
引理1.兩個非空子串u和v(length(u)<=length(v))是終點等價的,當且僅當u在字串s中僅作為w的字尾出現。
引理2.考慮兩個非空子集u,w(length(u)<=length(w))。它們的終點集合不相交,或者endpos(w)是endpos(u)的子集。進一步地,這取決於u是否是w的字尾:
引理3.考慮乙個終點等價類。將該等價類中的子串按長度遞減排序。排序後的序列中,每個子串將比上乙個子串短,從而是上乙個字串的字尾。換句話說,某一終點等價類中的字串互為字尾,它們的長度依次取區間[x,y]內的所有數。
引理4.字尾鏈結組成了一棵以t_0為根的樹。
引理5.如果我們將所有合法的終點集合建成一棵樹(使得孩子是父母的子集),這棵樹將和字尾鏈結構成的樹相同。
狀態的數量:
由長度為n的字串s建立的字尾自動機的狀態個數不超過2n-1(對於n>=3)。
轉移的數量:
由長度為n的字串s建立的字尾自動機中,轉移的數量不超過3n-4(對於n>=3)。
定理1.dawg(s)中字尾鏈結組成的樹就是字尾樹st(rev(s))。
定理2.圖dawg(s)的邊都能用字尾樹st(rev(s))的擴充套件指標表示。另外,dawg(s)中的連續轉移就是st(rev(s))中反向的字尾指標。
定理3.使用字尾自動機dawg(s),我們可以用o(n)的時間構建字尾樹st(rev(s))。
定理4.使用字尾樹st(rev(s)),我們可以用o(n)的時間構建字尾自動機dawg(s)。
*/#include
#include
#include
#ifdef win32
#define ll "%i64d"
#else
#define ll "%lld"
#endif
const
int n=2e6+5
;typedef
long
long
ll;char
s[n];
inta[n],c[n],size[n],n;
ll ans=0
;inline
int max(int x,int
y)struct
suffixautomaton
}size[np]=1
; }
void
build()
void
calc()
printf(ll "\n
",ans);
}}sam;
intmain()
字尾自動機SAM
原理詳細的可以看史上最通俗的字尾自動機詳解 想看懂還是要花很久。實現 include include using namespace std const int maxn 2000010 struct node nodes maxn int las 1 tot 1 char st maxn void...
SAM 字尾自動機
這玩意還真的好玄學,看了半天,也就看了個大概吧 確實很妙 總算理解了parent樹,但是關於sam的dag的性質的證明並沒有看太懂,也沒有特別明白。update 又看了一會,原來是自己把定義搞錯了,字尾自動機其實是在滿足以下條件的最簡狀態,主要是難構造,掌握構造 就好了,證明就不管了c。條件如下 摘...
字尾自動機sam學習小記
顧名思義,字尾自動機就是可以識別原串所有字尾的自動機,最後回到達葉子狀態,同時也可以識別所有連續子串。線性。由構造方法可知點數是線性的。構出sam後除了主鏈,即代表原串的鏈,其他的邊要麼就是構成了乙個新的字尾,要麼就是連線若干條構成了乙個新的字尾的邊,形成乙個類似樹的結構,所以邊也是線性的。很多性質...