正睿暑期集訓2
串
最小表示法
求串的迴圈同構串中字典序最小的串。
\(O(n)\) 線性掃一下即可。Lyndon一下也行。
Manacher
P4287 [SHOI2011]雙倍迴文
本質不同的迴文串數量是線性的(Manacher 的時間複雜度保證的來源)。考慮在Manacher右端點增加的時候判讀阿尼下是否是雙迴文串。
P5446 [THUPC2018]綠綠和串串
\(f_k\) 表示原串有沒有以 \(k\) 為中心,\(min(k,n-k+1)\) 為半徑的迴文串。Manacher一下即可。
然後我們發現對於長 \(r\) 的初始串,我們需要 \(f_r,f_{2r-1},f_{2(2r-1)-1}...\)
ExKMP / Z-Function
對於給定字串 \(S\),對於 \(S\) 的每一個字尾,用線性批量實現和原串進行LCP匹配。
從左往右掃 \(S\),依次計算出 \(S\) 每次向右平移後的與原串與其對齊的 \(LCP\)。維護一個 \(j\) 代表上次右端點最靠右的點,然後每次擴充套件從 \(z_{i-j}\) 長度開始擴充套件(不用從 \(1\) 開始)。
P2375 [NOI2014] 動物園
對於每個字首,求出其長度不超過一半的 border 個數。
可以用倍增跳border \(O(n\log n)\) 來做。
跑兩次 KMP,第一次普通記,第二次我們求不過半的最大 border(暴力跳是均攤的??)。然後隨便做即可。
P5334 [JSOI2019]節日慶典
求每個字首的最小表示。
維護一個候選點集使得只有候選點集內部的點才可能是最小表示的起點。
-
掃到 \(i\) 時,若對於 \(j,k\),使得 \(lcp(j,k)\le i-k\)(在 \(i\) 之前比出大小),則 \(j,k\) 只會保留一個。
-
若對於 \(j,k\),\(lcp(j,k)>i-k\) 且 \(2(i-k+1)>i-j+1\),那麼 \(k\) 永遠不會是答案。
- Proof:對於後面的位置 \(i'\),我們設 \(S[j,k]=B\),則 \(B\) 是 \(S[j,i]\) 的一個字首,則 \(S[1,i']\)
- Proof:對於後面的位置 \(i'\),我們設 \(S[j,k]=B\),則 \(B\) 是 \(S[j,i]\) 的一個字首,則 \(S[1,i']\)
所以候選點集點數一定會只有 \(O(log)\) 個。維護候選點集(掃一遍,判斷兩種情況),然後每次比較一下即可(做一堆比較&討論,需要用exkmp求LCP)。
求每個字首的最小字尾也是可以這樣做。主要在於能不能符合第二條結論。
Lyndon
Lyndon串:最小迴圈同構等於自己。
字串可以唯一拆分成若干個Lyndon串使得其所有Lyndon串字典序單調遞減。此為原串的Lyndon分解。
我們發現某個字首的最小字尾為其(?)
CF1466G Song of the Sirens
如果直接被 \(s_0\) 包含那麼很簡單。然後我們發現最終串一定是 \(s_0t_is_0...\) 的形式,我麼考慮把原串精簡成只包含 \(t\)(不斷 \(t_{lowbit(i)}\)),然後把詢問串的 \(s_0\) 部分也搞掉。我們發現 \(2^{lowbit}\ge |T|\) 的只會出現一次。然後?
AC Automaton
在trie上跑kmp。
P2414 [NOI2011] 阿狸的打字機
考慮怎麼在AC自動機上求一個串在另一個串中出現多少次。然後 trie 上 \(y\to root\) 鏈查詢有多少點在 \(x\) 所在 fail 樹的子樹。可以線上用主席樹或者離線用線段樹掃。
CF696D
考慮用 AC 自動機隨便 DP 一下。然後我們發現這個可以廣義矩陣乘優化。
薩菲克斯·資料結構
串的不同構子串數
對於兩個字尾,它們的同構的LCP一定是其更短的那個的長度。考慮能不能把每個字尾都弄成一個最小的表示(字典序最小的同構),之後就可以隨便做了。
考慮直接字尾排序,但是比較函式要重新玩。可以用二分+雜湊。所以問題歸為如何用雜湊判斷兩個子串同構。兩個串中,把所有字元按照第一個出現位置排序,然後用雜湊判斷同樣最先出現位置的字元的出現位置是否一樣。