(单调)队列优化多重背包

省流:复杂度是 \(O(NM)\) 的。

0

多重背包可以通过枚举选的个数做到 \(O(N^2 M)\)

转移是 \(f_j=\max(f_{j-k\times w_i}+v_i\times k)\)

1

注意到你每次转移好像只用到了一部分 \(f_j\),并且 \(j-k\times w_i\) 这个东西 \(j\bmod w_i\) 都相同,考虑将 \(j\bmod w_i\) 相同的 \(f_j\) 归为一类。

观察转移式子,令 \(j=k\times w_i+b\),转移变为 \(f_{j}=\max(f_{k\times w_i+b-x\times w_i}+x\times v_i)\)

考虑外面的 \(x\times v_i\) 怎么搞,显然是不能枚举 \(x\) 的,可以将 \(x\times v_i\leftarrow -(k-x)\times v_i+k\times v_i\),这样的话 \(k\times w_i\) 就不受影响,可以直接拿到外面去,变为

\[f_j=\max(f_{j-(k-x)\times w_i+b}-(k-x)\times v_i)+k\times v_i \]

再令 \(t=k-x\)

\[f_j=\max(f_{j-t\times w_i+b}-t\times v_i)+k\times v_i \]

注意 \(k-x>0\),这个过程可以用滑动窗口最大值维护,用个单调队列搞一搞即可。

复杂度可以证明是 \(O(NM)\) 的。

Solution

多重背包极大方案数,考虑直接按物品大小倒序枚举一个 \(i\),所有 \(w_j<w_i\) 的必须全部加进去,然后再对 \(w_j\geq w_i\) 的做多重背包计数。

\(f_{i,j}\) 表示前 \(i\) 种容量为 \(j\) 极大方案数,转移很简单:

\[f_{i,j}=\sum\limits_{l=0} ^ {s_i} f_{i-1,j-l\times w_i} \]

观察到每一个 \(i\) 只与前一个有关系可以滚掉第一维,剩下的多重背包可以通过上述方法优化。

代码参考这个的写的比较好。

模板题是 P1776,远古时期代码写的很丑不放了。

posted @ 2025-03-27 15:01  Iron_Spade  阅读(27)  评论(0)    收藏  举报