NOI2020 製作菜品 題解

2022-05-27 14:57:11 字數 2129 閱讀 1386

題意分析

給出 $n$ 個數和 $m$ 個 $k$ ,可以某些 $k$ 拆兩個正整數,使得拆後的數可以拼成給出的 $n$ 個數。

思路分析

上面的解釋是因為這樣寫比較方便,實際上按照題意應該是用 $n$ 個數拆分拼成 $m$ 個 $k$ 。

觀察資料範圍,發現有 $m\geq n-2$ 的限制和 $m\geq n-1$ 的部分分,考慮從這裡切入分析。

先分析 $m\geq n-1$ 的情況。令 $d_,d_$ 分別表示最小的 $d$ 和最大的 $d$ 。

很容易想到乙個貪心,若 $d_

如何證明這個貪心是正確的?

可以證明當 $m\geq n$ 時, $d_\geq k$ ,即與 $d_$ 配對後一定有剩餘,因此此時每次只會僅讓 $m$ 減 $1$ ( $d_\geq k$ )或 $n,m$ 各減 $1$ ( $d_

若 $m=n-1$ ,可能會出現 $d_+d_\leq k$ 的情況。可以證明此時 $d_+d_\geq 0$ ,因此只會出現 $d_+d_=k$ 的情況,這也說明了 $m=n-1$ 的情況下一定有解。這樣就會有 $n$ 減 $2$ 而 $m$ 減 $1$ ,轉化為 $m=n$ 。但是根據之前的分析,當 $m=n$ 時有 $d_\geq k$ ,而之前的 $d_< k$ 。因此這種情況當且僅當 $n=2$ 時會發生,即當前拼完之後就沒有剩餘的 $d$ 了,此時用剩下的兩個 $d$ 拼成乙個 $k$ 即可。另外,可以證明此時 $d_

綜上,根據這個貪心策略,可以使 $m\geq n-1$ 所有情況不斷向 $m=n-1$ 靠近,進入 $m=n-1$ 情況後就會保持不變,直至 $n=2$ ,此時用剩下的兩個 $d$ 拼成乙個 $k$ 即可,一定有解。用 set 等資料結構優化,時間複雜度 $o(m\log n)$ 。其實暴力 $o(mn)$ 也可以過

題目中的 $\sum d_i =m*k$ 是個很重要的性質,上面的「可以證明」都可以根據這個性質來證明。

接下來分析 $m=n-2$ 的情況。

可以想到把這種情況劃分成兩個獨立的 $m=n-1$ 的情況進行求解,此時兩部分的 $d$ 是沒有重合的。會不會有重合的情況呢?若存在這種情況,即從第二個 $k$ 開始,每次配對只能多用乙個 $d$ ,最後只能用 $n-1$ 個 $d$ ,顯然是不可能把 $d$ 全部用完的,因此不存在這種情況。

如何劃分?

分析這個策略,發現實質是要找到乙個集合 $s$ 使得 $\sum_ d_i=(|s|-1)*k$ , $|s|$ 表示集合 $s$ 的大小,即前面的 $n$ ,而不在這個集合內的元素就歸到另乙個集合。移項整理可以得到 $\sum_ (d_i-k)=-k$ 。看到這個式子很容易想到 01 揹包。用 bitset 優化,時間複雜度 $o(\frac)$ 。然後按照貪心策略分別求解,總的時間複雜度是 $o(\frac+nlogn)$ 。注意,由於可能會出現負數,因此要將所有數處理為正數再進行 dp 。

綜上,若 $m\geq n-1$ ,直接按照貪心策略進行求解;否則,用 01 揹包將所有的 $d$ 劃分成滿足 $\sum_ (d_i-k)=-k$ 的兩個集合,再按照貪心策略分別求解,此時一定有解。若找不到滿足條件的集合,則無解。

#include#include#include#include#includeusing namespace std;

const int n=600,m=2e6+5e5;

int t,n,m,k;

int d[n],v[n];

bool pd[n];

multiset> s;//維護 d_min 和 d_max

void solve()

if(minv && s.size())//還沒解完

}}//貪心處理

void parti()

int now=m-k;

s.clear();

for(int i=n;i;i--)//倒著來,找到乙個滿足條件的集合

if(f[i-1][now-v[i]])

solve();s.clear();

for(int i=1;i<=n;i++)//找另乙個集合

if(!pd[i])

s.insert(make_pair(d[i],i));

solve();

}int main()

}return 0;

}

NOI 2020 製作菜品 揹包dp

觀察資料範圍可以發現 m n 1,m n 2,m geq n 是三個比較特殊的資料點,那麼就找這三個點的規律 懶得寫了,直接放 zhq 的 luogu blog 了 然後就只剩下 m n 2 了,還是懶得寫了.原來是記 dp i j k 表示前 i 個選 j 個和為 k 的方案數,可以通過柿子轉換 ...

NOI2020 簡要題解

a 首先不難發現乙個暴力動態規劃的做法 記 f 表示第 i 天 當前在第 j 座城市所獲得的最大收益 有轉移方程 f max u cost i extra 發現 w 非常小 考慮拆點。將每個點拆成 w 個點 那麼一共會有至多 5n 個點。接著 考慮矩陣乘法 事實上 將求和運算改為 max 運算 並將...

NOI2020 美食家 題解

題意分析 給出乙個帶權有向圖,要求從節點 1 出發,經過恰好 t 的邊權和,回到節點 1 求可經過的最大點權和。特別地,經過的邊權和達到部分特殊數時,會有某個點的點權發生改變。思路分析 樸素演算法 設 f 表示在節點 j 經過的邊權和為 i 時可經過的最大點權和。很容易可以得出 dp 方程 f ma...