背包,子集和以及 (max, +) 卷积在特殊情形下的求法

背包,子集和以及 (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}]\) 即可。

posted @ 2022-02-01 20:51  wlzhouzhuan  阅读(2848)  评论(3编辑  收藏  举报