字尾自動機SAM

2021-09-29 10:29:34 字數 2224 閱讀 2697

原理詳細的可以看史上最通俗的字尾自動機詳解

想看懂還是要花很久。

實現

#include

#include

using

namespace std;

const

int maxn =

2000010

;struct node

}nodes[maxn]

;int

las(1)

,tot(1

);char st[maxn]

;void

add(

int c)}}

intmain()

題目

p3804 【模板】字尾自動機

每個結點的len表示出現過的最長的子串的長度,每個節點的子樹大小表示出現的次數,相乘就是答案。

#include

#include

using

namespace std;

const

int maxn =

2000010

;struct node

}nodes[maxn]

;int

las(1)

,tot(1

);int to[maxn]

, nx[maxn]

, s[maxn]

, e;

long

long ans, cnt[maxn]

;char st[maxn]

;void

adde

(int x,

int y)

void

add(

int c)}}

void

dfs(

int rt)

if(cnt[rt]

>

1) ans =

max(ans, cnt[rt]

* nodes[rt]

.len);}

intmain()

p3975 [tjoi2015]弦論

首字元越小,排名就越小。首字元相同子串肯定會排在一起,所以用k減去以每個字元為首字元的子串數sum,當k所以只要統計出每個結點的sum就好了。

t=0。sum[ i ] = 26個孩子的sum + 1。就是相當於在最前面加了乙個字元c,這樣以c為開頭的子串就是c+str,str不為空時,其數目就是孩子的sum之和,str為空時,就對應了+1,表示加了c後增加的子串c本身。

t=1。sum[ i ] = 26個孩子的sum + cnt[ i ], cnt的含義就是上題中cnt的含義,cnt[ i ] 表示子串中c出現的次數。

#include

#include

using

namespace std;

const

int maxn =

1000010

;struct node

}nodes[maxn]

;int

las(1)

,tot(1

);int to[maxn]

, nx[maxn]

, s[maxn]

, e;

int tt, k;

long

long cnt[maxn]

, sum[maxn]

;char st[maxn]

;void

adde

(int x,

int y)

void

add(

int c)}}

void

dfs1

(int rt)

}void

dfs2

(int rt)}}

intmain()

int r =1;

cnt[r]=0

;while

((k -

= cnt[r]

)>0)

return0;

}

這裡用了兩次dfs去統計cnt和sum,也可以對所有結點根據len做一次從小到大的排序,len大的肯定在parent tree的下面,所以就可以像拓撲排序那樣,從下往上統計cnt和sum。每個結點ch指向的結點len肯定大於自身的len,所以這樣也可以統計sum。

SAM 字尾自動機

好文 luogup3804 定義.對給定字串s的字尾自動機是乙個最小化確定有限狀態自動機,它能夠接收字串s的所有字尾。對給定字串s的字尾自動機是乙個最小化確定有限狀態自動機,它能夠接收字串s的所有字尾。某一狀態t 0被稱作初始狀態,由它能夠到達其餘所有狀態。自動機中的所有轉移 即有向邊 都被某種符號...

SAM 字尾自動機

這玩意還真的好玄學,看了半天,也就看了個大概吧 確實很妙 總算理解了parent樹,但是關於sam的dag的性質的證明並沒有看太懂,也沒有特別明白。update 又看了一會,原來是自己把定義搞錯了,字尾自動機其實是在滿足以下條件的最簡狀態,主要是難構造,掌握構造 就好了,證明就不管了c。條件如下 摘...

字尾自動機sam學習小記

顧名思義,字尾自動機就是可以識別原串所有字尾的自動機,最後回到達葉子狀態,同時也可以識別所有連續子串。線性。由構造方法可知點數是線性的。構出sam後除了主鏈,即代表原串的鏈,其他的邊要麼就是構成了乙個新的字尾,要麼就是連線若干條構成了乙個新的字尾的邊,形成乙個類似樹的結構,所以邊也是線性的。很多性質...