今天終於把這週的坑填了,同樣看了很多部落格,這裡就不詳細總結了,就簡單整理一下了。
應用: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 罪...