1. 程式人生 > 其它 >21.7.8 t1

21.7.8 t1

tag:SAM,矩陣乘法,分塊


首先我們要知道一個 trick,如何把兩個 SAM 拼起來。

大概就是對於第一個 SAM 上的所有點,如果某個字元 \(c\) 沒有出邊,就連向第二個 SAM 的根結點的 \(c\) 出邊指向的點。

這樣最後會構造出來一個自動機,每一條路徑都對應著一個題目中要求的字串。(為了方便,可以倒著構造)


先考慮如何求 \(f(l,r)\)

暴力就是直接從右往左 dp。

然後仔細觀察會發現,第 \(i\) 個 SAM 的 dp 值,只與它的形態和第 \(i+1\) 個 SAM 的根的兒子的 dp 值有關。

也就是說 \(f[root_i]= a_1f[son[root_{i+1}][1]]+\cdots+a_Tf[son[root+{i+1}][T]]+1\)

所以可以用矩陣的形式,表示出第 \(i+1\) 個 SAM 的根的兒子,對第 \(i\) 個 SAM 的根的兒子的貢獻,而矩陣只與第 \(i\) 個 SAM 的形態有關。

這個部分可以 \(O(nT^2)\) 求出來。(hehezhou說可以 \(O(nT)\),不過不重要)

於是可以 \(O(lognT^2)\) 的時間求出 \(f(l,r)\)


然後要求 \(\sum_{l,r}f(l,r)\),相當於求一個類似於 \(\sum_{l,r}\prod_{i\in[l,r]}A_i\) 的東西。

再多維護一點東西就行了,所以實際上只是比求 \(f(l,r)\) 多了億點常數。

可以分塊維護。

十分卡常。


誰想寫這個毒瘤的程式碼啊!