字尾自動機學習

2021-09-25 21:02:26 字數 1589 閱讀 9872

今天終於把這週的坑填了,同樣看了很多部落格,這裡就不詳細總結了,就簡單整理一下了。

應用:1、存在性查詢:給定文字t,詢問格式如下:給定字串p,問p是否是t的子串。 直接按著路徑走,看是否存在即可

2、不同的子串個數:對於每乙個節點即為:len[i] - len[fa[i]] 加和即可

3、不同子串的總長:這裡我是通過len[i] 和 fa 來求得

問題.給定字串s,找到和它迴圈同構的字典序最小字串。

複雜度要求.o(length(s)).

演算法.我們將字串s+s建立字尾自動機。該自動機將包含和s迴圈同構的所有字串。

從而,問題就簡化成了在自動機中找出字典序最小的,長度為length(s)的路徑,這很簡單:從初始狀態開始,每一步都貪心地走

,經過最小的轉移。

6、出現次數查詢:按照路徑找,num即為次數

7、首次出現位置查詢:可以在開乙個陣列,在插入的時候直接記錄即可

8、所有出現位置查詢:講解:

9、查詢不在文字**現的最短字串

#include using namespace std;

typedef long long ll;

const int n = 1e5 + 10;

struct sam

n = 0;

last = 1;

tot = 1; // 1是起始點 空集

fa[1] = 0;

len[1] = 0;

} void insert (int c)

} last = x;

} void getposnum()

void getsum()

} void getsubnum()

void getmaxx()

void getsublen()

// cout << sublen << endl;

} // 兩個串最長公共子串

int compare(char str)

res = max(res, cnt);

} // printf("%d\n", res);

return ans;

} /* 多個串

int compare(char str)

dp[p] = max(dp[p], cnt);

} for(int i = tot; i >= 2; i--)

dp[fa[i]] = max(dp[fa[i]], min(dp[i], len[fa[i]]));

for(int i = 2; i <= tot; i++)

return res;

} */

void get_kth(int k) }}

} cout << s << endl;

}}sam;

char s[n];

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 罪...