只講貪心做法。
一、反悔貪心
考慮如何使選的星星總數多一。顯然,有如下幾種方式:
-
選一個之前沒選過的位置 \(i\),答案加上 \(a_i\)。
-
選一個之前選過一次的位置 \(i\),答案加上 \(b_i-a_i\)。
-
對於一個之前選過一次的位置 \(i\),再找到一個沒有選過的位置 \(j\),反悔掉 \(i\),並選兩次 \(j\),答案加上 \(b_j-a_i\)。
-
對於一個之前選過兩次的位置 \(i\),再找到一個沒有選過的位置 \(j\),反悔掉 \(i\) 的第二次選擇,並選兩次 \(j\),答案加上 \(b_j-(b_i-a_i)=b_j-b_i+a_i\)。
總結一下,我們需要分別維護 \(a_i,b_i,-a_i,a_i-b_i,b_i-a_i\) 的最值,使用五個堆即可。但是每個策略可能會對多個堆進行修改,比較複雜,不推薦。
時間複雜度 \(O(n\log n)\)。
二、直接貪心
考慮每次選兩個星星,那麼我們需要權衡的是選 \(a_i+a_j\) 還是 \(b_i\)。
定義:\(2\) 物品表示根據以上選擇方式,一次用掉 \(b_i\),對答案貢獻為 \(2\) 的物品,剩下的都是 \(1\) 物品(如果其 \(b=2\),會分成 \(a\) 和 \(b-a\) 兩次選)。
開兩個堆,儲存 \(1\) 物品和 \(2\) 物品,然後每輪選擇進行如下過程:
-
記錄每個數是作為 \(2\) 物品被扔掉還是 \(1\) 物品。然後對於每個堆,把所有不合法的扔掉。
-
取出 \(1\) 堆的最小值和次小值 \(a_{mn},a_{se}\) 和 \(2\) 堆的最小值 \(b_{mn}\)(若不存在視為 \(+\infty\))。
-
若 \(a_{mn}+a_{se}\le b_{mn}\):記錄下每個數被選的次數,令 \(a_{mn},a_{se}\) 對應的 \(cnt\to cnt+1\),並標記為作為 \(1\) 物品使用。若此時 \(cnt=1\),說明選擇的是 \(a\),再將 \(b-a\) 扔進去。然後把 \(b_{mn}\) 扔回去(如果是 \(+\infty\),忽略)。
-
否則:使用 \(b_{mn}\),設定其 \(cnt=2\),作為 \(2\) 物品被使用。然後將 \(a_{mn},a_{se}\) 塞回去。
這樣選擇方案就輸出 \(cnt\) 即可。
但是這樣做有一個問題:如果 \(w\) 是奇數怎麼辦。此時我們可以加入一個值和編號都為 \(0\) 的 \(1\) 物品進去,並標記 \(cnt=1\),這樣它就只會被用一次。
時間複雜度 \(O(n\log n)\)。
Code