本文於 github 部落格同步更新。
A:
學生大戰一個半小時未果,結束前半小時發現是打表找規律。
就是分討一下,首先大於 \(1\) 的數不能超過兩個,若有兩個則其中一個必定為 \(2\),然後看一下 \(1\) 的個數是不是 \(3\) 的倍數即可。
B:
拆貢獻,分為 \(u\rightarrow lca\) 和 \(lca\rightarrow v\),前者需要求出 \(S[1, i]\) 作為子序列出現了多少次,後者需要求出 \(S[i, |S|]\) 作為子序列出現了多少次,兩者是對稱的。
對於每個 \(u\),求出 \(u\) 到根的路徑上有多少個子序列為 \(S[l, r]\),記為 \(f_{u, l, r}\),這個陣列容易在 \(O(n |S|^2)\) 內的時間預處理。
查詢時考慮 \(f_{u, 1, i}\) 代表的 \(S[1, i]\) 在 \(u\) 到 \(lca\) 和 \(lca\) 父親到根兩條路徑之間的分佈,比如 \(u\) 到 \(lca\) 上有 \(S[1, j]\) ,\(lca\) 父親到根有 \(S[j+ 1, i]\),後者預處理時已經被求出來了,因此可以容斥掉這部分貢獻,總時間複雜度 \(\mathcal O(n \log n + (n + q) |S|^2)\)。
C:
啟發式分治,每次找到區間最大值 \(i\),那麼區間內包含 \(i\) 的合法區間不超過 \(\log\) 個,然後每次選擇 \(i\) 左右兩側較短的一側,列舉區間和,判斷另一端點是否在區間內,直接轉移即可。
需要一開始將所有字首和塞到 \(map\),不能分治時現塞,因為區間長度無法保證。
D:
無法戰勝。