「BalticOI 2022 Day1」Uplifting Excursion 物品 题解

感谢 此神仙 在这题上对我的帮助,这里表达对祂衷心的膜拜。

Description

传送门

Solution

妙妙题。

暴力: Subtask 1-2

注意到所有物品的重量总和不超过 1010000 1010000 1010000,于是就是个裸的多重背包。

使用单调队列优化的复杂度为 O ( N 4 ) O(N^4) O(N4),常数较大;使用二进制分组优化的复杂度为 O ( N 4 log ⁡ N ) O(N^4 \log N) O(N4logN),常数较小且好写。具体两个能拿多少分没试过。

简化版

首先思考一个简化版的问题:总重量不需恰好为 m m m,只需不超过 m m m

不难发现,此时我们可以直接贪心。具体来说,我们预先选上所有重量为负的物品,那么接下来,选中一个重量 V V V 为负的物品等价于将其丢弃,可以使总重量增大 ∣ V ∣ |V| V 并减少一个物品,单价为 − 1 ∣ V ∣ -\frac {1} {|V|} V1;选中一个重量 V V V 为正的物品,可以使总重量增大 V V V 并增加一个物品,单价为 1 V \frac 1 V V1。显然的,根据贪心的思想,我们要先尝试选单价大的,再尝试选单价小的,于是我们应先尝试选 1 , 2 , 3 , ⋯   , m 1,2,3,\cdots,m 1,2,3,,m 这些物品,再尝试选 − m , − m + 1 , ⋯   , − 1 -m,-m+1,\cdots,-1 m,m+1,,1 这些物品。至于 0 0 0 的话,我们在接下来的讨论中都默认不存在重量为 0 0 0 的物品,毕竟只需要将最终的答案加上其数量就好了。

于是我们解决了简化版。

正解

回到原题,当要求总重量恰好为 m m m 的时候,我们该怎么办呢?考虑先套用简化版,求出一组贪心解,再对贪心解进行调整。

于是问题转化为,该如何调整,使总重量增长至 m m m 且选出物品的总个数最大。显然的,一次调整,要么将一个物品给弃掉,要么将一个物品给加入,而无论是上述哪种变化,总重量的增值都在区间 [ − m , m ] [-m,m] [m,m] 中。注意到总重量的总增值(即 m m m 减去贪心解的总重量)也在这段区间中,那么这样一来,调整的次数就可以不超过 2 m + 1 2m+1 2m+1 了。这是因为,我们可以先贪心地排列各次调整的位置,使各处的前缀和均在 [ − m , m ] [-m,m] [m,m] 中;接着,若存在某两个不同时刻的调整,使它们对应的前缀和相同,那么在这两次调整之间(左开右闭)的调整就都是无意义的,可以将它们一起去掉;不断地执行上述删除操作,直到无法删除为止,调整的次数就被减少到不超过 2 m + 1 2m+1 2m+1 了。

既然调整次数只有 O ( m ) O(m) O(m) 级别,那么各次调整的增量的绝对值之和就是 O ( m 2 ) O(m^2) O(m2) 级别的。所以,我们只需要跑一遍多重背包,就能调整出最优的方案了。

若使用单调队列优化多重背包,那么时间复杂度 O ( m 3 ) O(m^3) O(m3),可以通过本题。实测二进制分组优化也能过,而且跑得还很快。

Code

提交记录

Summary

启发:

  1. 遇到这种看似“经典”的题,正解不一定是经典的,要把思维打开,不能太局限。
  2. 有些时候,无法贪心就要考虑 dp,而无法 dp 也许要考虑贪心。
  3. 尝试将题目弱化一下,或许能够有利于走向正解。
  4. 本题的精髓——先贪心构造出一组不超过/不小于的解,接着发现不需要做过多的调整,从而问题"变小",就可以通过 dp 及其他技巧将其调整为一组最优的合法解了。感觉这个思想很值得推广应用。

你可能感兴趣的:(贪心,动态规划,贪心算法,算法)