題目大意:給出 m 個區間,現在可以選擇兩段長度為 k 的區間進行覆蓋,記為 a 和 b,對于每個區間來說,假設被 a 覆蓋的長度為 len_a,被 b 覆蓋的長度為 len_b,假設 len_a > len_b,那么其將會被 a 覆蓋,且提供 len_a 的貢獻,反之被 b 覆蓋且提供 len_b 的貢獻,問如何選擇 a 和 b 可以使得總貢獻最大
題目分析:比較顯然的一個 n^3 的暴力就是:O( n ) 枚舉 a,O( n ) 枚舉 b,最后 O( n ) 枚舉每個區間計算貢獻
考慮優化,假設我們已經枚舉好了 a,記為 [ L , R ],再計算每個區間與其交集,len[ i ] 表示的是第 i 個區間與 [ L , R ] 的交集,不過此時我們默認的是所有 len[ i ] > 0 的區間都是被 a 覆蓋的,所以我們考慮差分維護一下貢獻,我們最后的目標是為了得到一個數組 len_b,len_b[ i ] 代表的是,如果 b 的左端點或右端點選擇到了點 i 時,不與 a 的覆蓋所沖突的最大貢獻,這句話可以這樣理解:依然假設 len_a 和 len_b 是與某段區間交集的長度,顯然?len_a?就是剛剛求出的 len[ i ]?了:
如果 len_a >= len_b:那么此時該區間選擇被 a 覆蓋是更優的,所以?b 不做貢獻
如果 len_a < len_b:那么此時被區間 b 覆蓋是更優的,且被 b 覆蓋后,貢獻增加了 len_b - len_a
所以我們的目標就是維護出 len_b[ i ] 這個數組即可
畫兩張圖應該就可以包含所有情況了
我們這里的 len_b[ i ] 代表的是,b 的右端點取到點 i 時的?貢獻差
不難看出上述兩個圖中,當點 i 取到綠色區域時,隨著 i 右移,貢獻會不斷加一,當點 i 取到黃色區域時,貢獻會不變,當點 i 取到藍色區域時,會隨著 i 右移貢獻不斷減一,這個自己想一下應該就能想過來了
所以對 len_b[ i ] 初始時維護一個二階差分,然后兩次前綴和復原即可,上面的幾個關鍵位置都特地寫出來了,直接實現即可