原理詳細的可以看史上最通俗的字尾自動機詳解
想看懂還是要花很久。
實現
#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後除了主鏈,即代表原串的鏈,其他的邊要麼就是構成了乙個新的字尾,要麼就是連線若干條構成了乙個新的字尾的邊,形成乙個類似樹的結構,所以邊也是線性的。很多性質...