小組聯考 最優卡組

2021-09-29 06:29:12 字數 3638 閱讀 8239

【記憶體限制: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

6654

43

樣例解釋$chitanda$ 有 $3 \times 3$ 種選法,能力值分別為 $1 + 2, 1 + 3, 1 + 3, 3 + 2, 3 + 3, 3 + 3, 5 + 2, 5 + 3, 5 + 3$。

對於所有資料,$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函式 可對線進行平移 輸出該線各...