Update On 20210120:發現自己各種亂用 \(O\),修改了一下。
做 cmd 的某字符串題 的時候寫了個復雜度基於標題的算法,當時以為這是線性的。后來看題解里有人寫是 \(1.5\) 次方的,就仔細思考了一下。后來感覺這東西挺簡單的(
考慮以下問題:
給定模板串集合 \(S\),保證其中所有字符串的長度和不超過 \(L\)。對其建立廣義 SAM,設其節點集合為 \(V\),\(u \in V\) 所代表的字符串集合中最長的字符串為 \(longest_u\),則考慮求出 \(\sum_{s \in S} \sum_{u \in V} [longest_u \subseteq s]\) 的漸進上界,其中兩個字符串 \(s,t\) 滿足 \(s \subseteq t\) 當且僅當 \(s\) 是 \(t\) 的子串。
在廣義 SAM 的部分問題中可能會使用復雜度等於該值的算法:例如計算子串在多少個模板串中出現,可以建立廣義 SAM 后對於每一個模板串找到其所有前綴在廣義 SAM 上的節點,然后從它們開始暴力跳 parent 樹算貢獻,並給每個訪問了的節點打上訪問標記保證在同一個模板串的計算過程中一個點不經過兩次。這個算法的復雜度上界就是上面問題提到的漸進上界。
給出結論:\(\sum_{s \in S} \sum_{u \in V} [longest_u \subseteq s] = O(L^{1.5})\)。
證明:分成兩個部分,第一個部分證明漸進上界不高於 \(L^{1.5}\),第二個部分構造一個漸進為 \(L^{1.5}\) 的模板串集合。
Part 1.
首先通過廣義 SAM 的構造容易知道廣義 SAM 的節點數是 \(O(L)\) 級別的。那么某個串 \(s \in S\) 在廣義 SAM 上遍歷的節點數不會超過 \(\min\{|s|^2 , L\}\)。接下來分兩個情況考慮:
-
對於 \(|s| > L^{0.5}\) 的字符串,字符串數量不超過 \(L^{0.5}\),節點數不超過 \(L^{1.5}\);
-
對於 \(|s| < L^{0.5}\) 的字符串,由於 \(x^2\) 是下凸函數,因此遍歷節點數在恰有 \(L^{0.5}\) 個長度為 \(L^{0.5}\) 的字符串上取到上界,否則可以通過調整得到更大的節點數。故上界為 \(L^{1.5}\)。
綜上漸進上界不會超過 \(L^{1.5}\)。
Part 2.
構造實際上是簡單的。構造一個長度約為 \((2L)^{0.5}\) 的隨機字符串,然后 \(S\) 中包含其所有后綴即可。這樣可以保證每個字符串的基本所有子串都會在廣義 SAM 中。實測在 \(L = 45000,5 \times 10^5 , 2 \times 10^6\) 時該構造方式得到的遍歷次數都可以達到 \(0.5L^{1.5}\) 左右。