09-03 題解

Bubble_e發表於2024-09-03

09-03 題解

比賽地址

補題地址

這回打算改變一下方式, 從寫 "怎麼做題" 變成 "怎麼想題"

T1

什麼樣的兩個 \(a_i\) 能被合併到一個 Bug 上?

很簡單 (不過我也想了好一會), mod 2 同餘的兩個可以合併在一起

為了培養最強 Bug, 肯定不能往上疊負數, 所以上述內容針對序列中的所有正數

確定了選哪些數, 最少的操作步數是確定的, 這裡不再贅述

如果序列裡沒有正數怎麼辦?

顯然只能選一個最大(絕對值最小)的負數(或 0)

但是注意, 對於值相同的若干個下標 \(i\), 他們對應的最小步數可能是不同的 (? 我也不確定)

T2

如果沒有 "傳送門" 該怎麼做 ?

這就變成了簡單的數連通塊個數, 並查集維護維護

有 "傳送門" 呢 ?

這就相當於在連通塊之間連上了一些有向邊

根據上述思路, 把每個連通塊縮成一個點, 確定該點能到達哪些點 (代表著連通塊), 查詢時看看所有可達的連通塊中包不包括終點即可

但是賽時我沒有想這麼多, 用了原理類似但實現不太一樣的方法 : 該連通塊內有哪些傳送門, 這些傳送門又能到達哪些傳送門, 所有可達的傳送門的出口是否存在和終點在一個連通塊裡的

T3

翻轉一個區間對整個序列的逆序對數有什麼影響 ?

區間內部的 "順序對" "和逆序對" 互換, 區間外不受影響

怎麼利用這個資訊 ?

這一點我沒想到, 所以只打了 \(O(n^2 log\ n)\) 的暴力

序列長度是 2 的冪次, 很適合分治 (形成一棵滿二叉樹)

對於一個分治區間, 計算他的左半部分對右半部分貢獻的順序對和逆序對

  1. 如果翻轉在左半邊或右半邊內部, 那麼這部分貢獻不變, 向下遞迴
  2. 如果翻轉包含了這個區間, 那麼逆序對和順序對的個數交換

暴力做每次詢問是 \(O(n\ log\ n)\) 的, 怎麼最佳化 ?

每次翻轉的區間是等長的, 他們在分治樹上位於同一層

可以先找到包含 \(l_i\)\(r_i\) 的所有塊的大區間, 在上面打個標記, 告訴他我在長度 (可用點的深度表示) 等於某某時進行一次翻轉

這就要求我們在每一個點上儲存他的子樹中深度為 \(x\) 的順序對和逆序對的和

幸好這樣做只會增加一個 log, 在 Push_up 時就可以處理出這部分資訊

Push_down 中有一些細節, 需要你 (我) 仔細思考一下