多重背包的二进制拆分优化
有N种物品 每个物品都有个数的限制An和重量Wn价值为Cn 给定一个重量 求最大价值或最小价值
我们可以把每个物品的个数An转化为二进制数 这个数表示成(2的0~k次方)+(An减2的k次方减1)
之后我们可以用这些数表示<=An 的任意一个整数(这是小学数奥)
把每一个物品都做同样的处理 问题就变成了一个01背包问题了
多重背包的单调队列优化
我们在写背包的时候一定知道当面对一个物品时 枚举<An 的每一个值K
对于每一个当前状态 可以转移的状态一定与当前状态对K取模的值是一样的(即同余)
那么就可以吧这些状态一个一个挑出来单独做
之后呢
让我们写一个单调队列
我们只对同余情况下两者差值<An的状态进行操作
所以需要把队头不在范围内的元素弹出即可(因为对于当前元素已不可行 那么后面一定不可行)
何以成为单调呢?
我们保证这个队列中靠近队头元素比靠近队尾的元素更优
什么是更优?
更优就是对于每一个要进队的元素 它的J(就是它的体积对K的商数)减去队尾的的元素的J 我们被这个值记为I
它的决策的结果一定比队尾元素的决策结果至少大I*Wn
否则队尾的决策就可以通过增加该物品的个数 达到比要进队的状态更优的解(因为靠近队头的元素一定比后面的元素更容易弹出所以如果状态比他劣丢弃即可)
如果队尾不如进队元素更优 那么弹出队尾元素
不断重复直到有一个元素比当前状态优或队列中没有元素 就把当前状态压入队列(队列中所存为下标)
让我们用代码整理一下思路:
for(int i=1;i<=n;i++)//枚举物品
for(int j=1;j<=a[i];j++)//枚举个数
for(int k=j;k<m;k+=a[i])//枚举可转移的状态
//弹出不符合的元素
dp[i][j]=do[i-1][p[l]]+(j-p[l])/w[i]* C[i]
//比较状态 压入对列
例题 poj1742(貌似是这个)
ST算法笔记
对于一堆状态 我们来找他的可转移最大值
我们令DP[I][J]为从I开始到I+2^J的最大值
那么我们就有如下方程
DP[I][J]=MAX(DP[I][J-1],DP[I+2^(J-1)][J-1])
可以画一个图来想一下 这样即使两边有重合也没有关系
越界也没有关系
比线段树好写多了