背包,子集和以及 (max, +) 卷積在特殊情形下的求法
子集和 1:總重量不太大
有 \(n\) 個物品,每個物品重量為 \(w_i\),且 \(\sum\limits_{i} w_i=C\)。你需要對於 \(k\in [1,C]\) 均求出是否存在子集和 \(=k\)。
時間復雜度 \(\mathcal O(\frac{C\sqrt{C}}{\omega})\),空間復雜度 \(\mathcal O(n+\frac{C}{\omega})\)。
我們對於相同重量的物品二進制分組,然后暴力 01 背包,用 bitset 加速即可。
時間復雜度證明:
不妨設重量為 \(w\) 的物品有 \(a\) 個,則 \(\sum\limits_{i=1}^{m} w_ia_i=C\)。二進制拆分后的物品數為 \(\sum\limits_{k=0}\sum\limits_{i=1}^{m} [a_i\ge 2^k]\)。
對於固定的 \(k\),滿足 \([a_i\ge 2^k]\) 的 \(i\) 有 \(\sqrt{\frac{C}{2^k}}\) 個,因此物品數 \(\sum\limits_{k}\sqrt{\frac{C}{2^k}}=\sqrt{C}\sum\limits_{k}2^{-k/2}\le \frac{\sqrt{2}}{\sqrt{2}-1}\sqrt{C}\)。
子集和 2:單個重量不太大
有 \(n\) 個物品,每個物品重量為 \(w_i\),滿足 \(w_i\le D\)。問是否存在子集和 \(=C\)。
時間復雜度 \(\mathcal O(nD)\),空間復雜度 \(\mathcal O(n+D)\) 或 時間復雜度 \(\mathcal O(\frac{n\sqrt{n}D}{\omega})\),空間復雜度 \(\mathcal O(n+\frac{\sqrt{n}D}{\omega})\)。
法一:
先找到最大的 \(k\) 滿足 \(\sum\limits_{i=1}^{k} w_i\le C\),問題轉化為能否從 \(\{-w_1,\cdots,-w_k,w_{k+1},\cdots,w_n\}\) 選出子集和 \(C-\sum\limits_{i=1}^{k}w_i\)。該做法的核心思想是:如果當前子集和 \(>C\),那么從 \(w_1\sim w_k\) 中選一些數減到 \(\le C\),否則從 \(w_{k+1}\sim w_n\) 中選一些數加到 \(>C\)。
我們定義 \(\text{can}(tot,l,r)\) 表示是否存在 \(\lambda_{l},\lambda_{l+1},\cdots,\lambda_{r}=\{0,1\}\) 滿足 \(\sum\limits_{i=1}^{l-1}w_i+\sum\limits_{i=l}^{r} \lambda_iw_i=tot\)。
性質 1:固定 \(tot,r\),則 \(\text{can}(tot,l,r)=1\) 的 \(l\) 為一段前綴。
我們定義 \(dp_{tot,r}\) 表示最大的 \(l\) 滿足 \(\text{can}(tot,l,r)=1\)(如不存在,\(dp=-1\))。考慮轉移。
性質 2:固定 \(tot,l\),則 \(\text{can}(tot,l,r)=1\) 的 \(r\) 為一段后綴。
據此有 \(dp_{tot,r}\le dp_{tot,r+1}\),於是有三類轉移:
- \(dp_{tot+w_{r+1},r+1}\leftarrow dp_{tot,r}\)
- \(dp_{tot,r+1}\leftarrow dp_{tot,r}\)
- \(dp_{tot-w_{l'},r}\leftarrow l'\ (l'\in [1,dp_{tot,r}))\)
我們發現第三類轉移有 \(\mathcal O(n)\) 條,但是對於固定的 \(tot\),我們在 \(dp_{tot,r}\) 時有意義的轉移只有 \(l'\in [dp_{tot,r-1},dp_{tot,r})\),否則可以在 \(dp_{tot,r-1}\) 的時候就轉移掉。
因此,對於固定的 \(tot\),第三類轉移總共有 \(\mathcal O(n)\) 條,因此時間復雜度是均攤 \(\mathcal O(nD)\) 的。
法二:
考慮隨機打亂這個集合,則過程中期望達到的最值為 \(\mathcal O(\sqrt{n}D)\),用 bitset 加速即可。
(max, +) 卷積
給定兩個長為 \(n\) 的序列 \(A,B\),求它們的 \((max,+)\) 卷積 \(C\)。保證 \(B\) 是凸函數。
時間復雜度 \(\mathcal O(n\log n)\) 或 \(\mathcal O(n)\),空間復雜度 \(\mathcal O(n)\)。
法一:
我們記 \(C_i\) 的決策位置(即 \(B\) 序列位置)為 \(f_i\),容易證明 \(f_{i-1}\le f_i\)。因此直接分治即可。
時間復雜度 \(\mathcal O(n\log n)\),空間復雜度 \(\mathcal O(n)\)。
法二:
考慮構建一個 \((2n-1)\times n\) 的矩陣 \(X\),滿足 \(X_{i,j}=A_i+B_{i-j}\)。我們想要的即為 \(X\) 的每行最小值。
由於 \(B\) 是凸的,所以 \(X\) 是完全單調矩陣,用 SMAWK 求解即可。
不過聽 Froggy 說 SMAWK 的效率被二分棧 / 分治吊打,所以可能 not practical。
時間復雜度 \(\mathcal O(n)\),空間復雜度 \(\mathcal O(n)\)。
01 背包:單個重量不太大
有 \(n\) 個物品,每個物品重量為 \(w_i\),價值為 \(v_i\),不同的 \(w_i\) 有 \(D\) 個。選出最大的子集 \(S\) 滿足重量和不超過 \(C\),且總價值最大。
時間復雜度 \(\mathcal O(n\log n+DC\log C)\) 或 \(\mathcal O(n\log n+DC)\),空間復雜度 \(\mathcal O(n+C)\)。
對於相同 \(w\) 的物品,我們肯定將 \(v\) 從大到小貪心取,圖像為一個凸函數。因此我們將背包在模 \(C\) 意義下分別做 \((max,+)\) 卷積即可。
完全背包:單個重量不太大
有 \(n\) 個物品,每個物品重量為 \(w_i\),價值為 \(v_i\),滿足 \(w_i\le D\)。選出最大的可重子集 \(S\) 滿足重量和不超過 \(C\),且總價值最大。
時間復雜度 \(\mathcal O(D^2\log C)\),空間復雜度 \(\mathcal O(n+D)\)。
注意到對於 \(i>D\),有 \(dp_i=\max\limits_{j+k=i} (dp_j+dp_k)\),且如果 \(|j-k|>D\),我們始終可以調整得到 \(|j-k|\le D\)。
因此通過 \([dp_{j-\frac{D}{2}},\cdots,dp_{j+\frac{D}{2}}]\) 以及 \([dp_{k-\frac{D}{2}},\cdots,dp_{k+\frac{D}{2}}]\),可以暴力卷積得到 \(dp_{j+k}\) 的值。
現在,假如我們知道了 \([dp_{k-D},\cdots,dp_{k+D}]\),它卷自己可以得到 \([dp_{2k-D},\cdots,dp_{2k+D}]\)。因此采用倍增的形式可以快速計算出 \([dp_{C-D},\cdots,dp_{C}]\),答案即為其中的最大值。
初始化的地方,暴力計算 \([dp_0,\cdots,dp_{2D}]\) 即可。