关于名字 #
名字看不懂无所谓,我看有一篇博客这么叫感觉有点道理就也这么叫了,dls 管这个叫数位背包,但那样叫就感觉有点自成一派,其实就是一种特殊的 01 背包。
引入 #
直接看一个例题:[HNOI2007]梦幻岛宝珠,题意就是一个容量很大的01背包问题,但w能写成 a×2b,a≤10,b≤30的形式。
这个特殊限制就开始暗示我们从二进制的角度考虑,我们要做的是将物品按b分组,从大到小,每次考虑一个分组里我物品。当对分组i进行dp时,设当前剩余的容量为k×2i,由于分组里物品重量都能写成a×2i的形式,所以只有容量的系数k会变化,所以我们可以只用系数来代表当前剩余容量。
其实最重要的限制是 a≤10,因为任何数都能写成 a×2b 的形式,只不过 a 很大罢了。 a很小这个限制就确保了整个组里所有物品的重量之和不超过 100×10×2b(100来自于题目中最多有100个物品的限制)。再结合上一段中用系数表示容量的方法,这样重量的状态就从标准01背包做法的109缩小到了1000!这就是本题的核心思想。
接下来我们说状态转移,令dpi,j为考虑完i及以上的组之后,背包剩余容量为j×2i时能得到的最高价值(j的上限为1000,因为再多了后面的物品也用不完)。在一个分组内dp时就是常规的01背包,重点在于从i转移到i−1:当前剩余容量j×2i 变成 2×j×2i−1+si−1×2i−1=(2×j+si−1)2i−1,其中si−1代表背包总容量二进制表示的第i−1位,现在加上si−1×2i−1是因为之前这部分容量太小了用不上,在考虑i−1组的时候就能用上了。用代码表示一下转移的话就是
另一道题 #
接下来看一道不是很“背包”的题CF1670F. Jee, You See?,核心思路不变。变了的地方及对应的解决方法:
- 最大重量变成了方法数
- 物品变成了数组中第i位1的个数,可以选从0到n个
- 相当于上面的题中的a从0到n各一个,遍历即可
- 异或的限制
- 如果当前位是1,那就选1,3,5,…个,如果是0就选0,2,4,…个