這裡裝的是一些不太好分類的。
problem 1
給你 \(n\) 個序列,第 \(i\) 個序列的長度為 \(m_i\),要求在每個序列中選擇一個數,每種選法的代價為選擇的 \(n\) 個數之和,請求出代價前 \(k\) 小的方案的代價之和。
\(1\le n,k \le 10^5,1 \le m_i \le 10\)。
對於 \(k \le 500\) 的情況這是一個比較常見的貪心問題,我們使用堆合併 \(n\) 次即可。
於是我們嘗試用堆來解決這個問題。
首先我們可以知道最小值,然後我們可以在一個一個去改變每一個堆選的值。
定義狀態 \((val,x,y)\) 為當前合併出來的數為 \(val\),現在在第 \(x\) 個堆,這個堆選擇的是第 \(y\) 個數。
我們有以下三種情況進行轉移:
-
\(y < len_x\):此時我們可以選擇這個堆的下一個數並且拋棄這個數。
-
\(x < n\):此時我們可以選擇下一個堆,並且將選擇下一個堆的第二個數.
-
\(x < n\) 且 \(y = 1\):我們在這個堆撤銷次小的,選擇最小的,然後選擇下一個堆中次小的。也就是跳過第 \(x\) 個堆。
這樣子就可以保證不重不漏,然後就可以求出前 \(k\) 小的方案之和了。
problem 2
先拋棄掉顏色只差大於 \(L\) 這個條件,先單獨看第二個條件。
看到第二個條件我們可以想到對於原圖建一棵 Kruskal 生成樹。不知道這個東西是啥的戳這裡。
現在我們加上那個條件。
我們列舉每一個新加出來的點,考慮他對答案的貢獻。
明顯的,貢獻就是它的左邊子樹和右邊子樹各選出來一個點能組成一個有好點對的方案數量乘上這個點的權值。
我們可以列舉它的左子樹中的葉子結點,然後再計算對面有多少個點是不滿足條件的。
由於一個子樹內的 dfs 序是連續的,所以說這個題目就被我們轉換成了二維數點問題。
細節有點多。扔個程式碼實現 -> code。