【記憶體限制:512 mib】
【時間限制:1000 ms】
【標準輸入輸出】
【題目型別:傳統】
【評測方式:文字比較】
$chitanda$ 有 $k$ 個卡包,第 $i$ 個卡包裡有 $c_i$ 張卡,每張卡有乙個能力值,其中第 $i$ 個卡包裡的第 $j$ 張卡具有 $a_$ 點能力值。
他準備選擇 $k$ 張卡牌的組合,其中每個卡包要選擇恰好一張卡牌。他希望這 $k$ 張卡牌的能力值之和盡量大,請你告訴他在所有可能的組合裡,能力值之和最大的 $n$ 個組合分別具有多大的能力值。
第一行包含兩個整數 $k$ 和 $n$,含義見題目描述。
接下來 $k$ 行,每行描述乙個卡包的資訊,其中第 $i$ 行的第乙個整數表示 $c_i$,接下來該行會有 $c_i$ 個整數,依次表示這個卡包裡每張卡的能力值。
輸出一行,包含 $n$ 個整數,相鄰兩個數字之間用空格隔開,其中第 $i$ 個整數表示第 $i$ 大的能力值之和。
樣例輸入
293樣例輸出1353233
887樣例解釋$chitanda$ 有 $3 \times 3$ 種選法,能力值分別為 $1 + 2, 1 + 3, 1 + 3, 3 + 2, 3 + 3, 3 + 3, 5 + 2, 5 + 3, 5 + 3$。6654
43
對於所有資料,$k \geq 2,$ $1 \leq n \leq \prod\limits_^,$ $c_i \geq 1,$ $1 \leq a_ \leq 10^9$ $(i = 1, 2, \cdots, k; j = 1, 2, \cdots, c_i)$。
考試的時候想到乙個很類似於正解的東西,預估時間複雜度 $o(nk)$ ,但是想到很多限制,結果**都不敢碼......
最後痛失 $50pts$ 。
接下來說一下這個思路吧。
$subsulotion#50pts$
首先,我們先將每個卡組內的卡從大到小排個序。
然後,我們再定義乙個數字串,定義不方便說,直接拿例子解釋
有這樣乙個數字串:
數字: $12345$
數串: $13211$
這個數串表示的意思就是:在這種情況下,第一組取的是第一大的,第二組取的是第三大的,第三組取的是第二大的......以此類推
那麼,毫無疑問,最大的能力值一定是 $11111$
然後呢?次大的呢?
我們不知道次大的是哪個,但是我們肯定可以保證次大在 $21111、12111、11211、11121、11112$ 中
我們把這些數串叫做子狀態
那麼這個思路就出來了:
把狀態放進優先佇列裡面,每次取出最大的狀態,輸出,再放進它的子狀態......重複 $n$ 次即可。
但是這樣呢,每個狀態會最多被放入 $k$ 次,為什麼?
舉個栗子:
狀態 $23426$
它可能被 $13426、22426、23326、23416、23425$ 放進去。
那麼時間複雜度大概是 $o(n\cdot k\cdot log)$
看看範圍,還可以過一半,挺好......
一道思路詭異的貪心題,但是這個思路也不是不可想,只是要分析到點上。
我們其實可以在 $50pts$ 的思路上加以改進。
首先,超時思路為什麼會時間複雜度高?
是因為同乙個狀態被最多放進了 $k$ 次。
那麼怎麼解決這個問題呢?
這裡有乙個最終的解決方法,先說出來,然後解釋其正確性以及如何思考。
首先,我們可以在輸入的時候得到 $k$ 個串 $a_$ 表示第 $i$ 組卡牌的能力值
將每個組內卡牌從大到小排序,然後設 $val_i=a_-a_$
具體意思就是 $val_i$ 表示第 $i$ 組中最大的牌減次大的牌的值
再按照 $val_i$ 從大到小把陣列順序重排
在處理完這些之後,我們來看怎麼放進狀態的子狀態
設我們有乙個狀態 $\overline$
其中 $×$ 不用管,就是來佔位置用的,而 $b$ 之前全是 $1$
那麼我們會對這個狀態做出三個轉移,其中乙個是特例:
最後把他們放入優先佇列,同樣地維護即可。
那麼這樣做有什麼好處嗎?
首先,它不會出現重複狀態被壓入優先佇列。
為什麼?
假設佇列中有這樣乙個狀態:$\overline$(注意不要和之前的狀態混淆了)
如果 $b≥2$ 且當 $b=2$ 時 $a≠1$ ,那麼它只有乙個前驅 $\overline=\overline$
但是如果 $b=2$ 且 $a=1$ 時,我們可以否決其前驅是 $\overline=\overline$ ,這個很好想
那麼它的祖先就有且只有 $\overline$ ,就是那種特殊子狀態
所以說,這樣轉移顯然每種狀態就只會出現一次
那麼,它還有什麼優勢呢?
又來舉同乙個栗子,我們有狀態 $\overline$
那麼,當不是特殊情況時,我們的轉移是 $\overline$ 或者是 $\overline$
那麼,這兩種狀態。是否都比 $\overline$ 小呢?答案是肯定的。
但如果是特殊情況:$\overline\rightarrow \overline$
這樣轉移的話,子狀態是否也是比前驅狀態小呢?
答案也是肯定的。
綜上,這個處理方案有兩點好處:
那麼我們看一看,其時間複雜度是不會超過 $o(3nlog)$ 的。
但是又有乙個問題:這個神仙思路是怎麼想到的呢?
首先,對於 $50pts$ 的思路是一定要想到的,然後對於時間複雜度進行分析。
時間複雜度 $o(knlog)$ ,首先這個 $n$ 是一定跑不掉的,然後 $log$ 也肯定是有的,因為我們始終要用堆進行維護。
那麼我們就要盡可能地將 $k$ 變小。
這個 $k$ 是跟子狀態有關的,那麼我們要盡可能減小子狀態的數量。
那麼,我們引入乙個比較好想的思路:每次只更改第乙個不是 $1$ 的位置
比如對於乙個狀態:$\overline$
那麼它的子狀態就是 $\overline$ 或者 $\overline$
但是有一種情況:$\overline$,在我們的子狀態定義中是夠不到的。
所以還要再定義乙個子狀態:$\overline$,再普遍一點:$\overline$
這樣我們就可以從$211..1$ 到 $1211...11$ 到 $1121...11$ ....到 $1111...2$,把這種特殊情況包含進去
但是這樣又會有乙個問題了,舉個栗子,狀態 $232$ 可以通過狀態 $241$ 得到,也可以通過 $231$ 得到,這樣就重複了。
所以為了避免重複,我們只在 $a=1,b=2$ 時進行最後一次子狀態下傳。
而將 $a=1,b=2$ 轉成 $a=2,b=1$ 的同時,又要保證先大後小,就加入了那個奇奇怪怪的排序方式。
$ac$ 思路就是這樣,**:
題解都打了那麼多,**卻寫不出來了......
LibreOJ 6254 最優卡組 堆
有n nn個卡包,第i ii個卡包裡有c ic i ci 張卡,每張卡有乙個能力值。現在從每個卡包裡面選一張卡,定義一種方案的價值為選的卡的能力值之和,求價值前k kk大的方案。n k ci 300000 n,k,sum c i le300000 n,k,c i 3 0000 0 很自然的想法是用乙...
提高組聯考1
每個字母分開考慮,一定至少有乙個字母不動,列舉不動的位置,向兩側擴充套件至最大,嘗試更新答案 注意無窮大的選擇 code include include using namespace std int sum 27 4005 cnt 27 char c 4005 int main int ans 0...
5 6 小組練筆1
背景 平面直角座標系 要求 定義乙個點類,資料成員至少包含 座標值x,y。函式成員至少包含 建構函式,move函式 可對點進行移動 定義乙個線類,資料成員至少包括 點類物件陣列指標 指向動態陣列的首位址 點的個數 n。函式成員至少包括 建構函式,複製建構函式,move函式 可對線進行平移 輸出該線各...