分治优化

概述

  • 分治优化常常在 dp 的转移有某种单向单调性时使用,通过类似整体二分的结构,确保每个决策点只在一条链上出现,从而加速转移。一般这种分治优化也有对应的二分栈形式,区别仅在于逆推和顺推。此部分在四边形不等式优化一节。

  • 分治优化本身还是一种非常有趣的 dp 实现方式。这一部分...我还不是非常了解,也是本节的重点。但似乎...这就是线段树分治?(如果确实,考虑将这边合并过去,毕竟这种分值处理的可不仅仅是 dp)。

例题

CF1442D Sum

  • 题意略。下面的复杂度分析里,因为 \(n,K\) 同阶,用 \(n\) 代替 \(K\)

  • 发现这个就是把我们广义多重背包的物品反了过来,更短的转移反而“性价比”更高。考虑利用四边形不等式。

  • 那么起式子,\(dp_{i,j}=\max_{k\leqslant j}(dp_{i-1,k}+v_{i,j-k})\)。这里不写那种四边形形式了,容易看出,交叉小于包含。

  • 当然 dp 的转移来源还是要推一下,盲猜有 \(k_{j-1}\geqslant k_j\),理由是取 \(l<l'\leqslant r<r'\),假设有 \(k_r=l,k_{r'}=l'\),推一下试试:

    • \(dp_{i-1,l}+v_{r-l}+dp_{i-1,l'}+v_{r'-l'}\geqslant dp_{i-1,l}+v_{r'-l}+dp_{i-1,l'}+v_{r-l'}\)

    • 左右消一下,得到 \(v_{r-l}+v_{r'-l'}\geqslant v_{r'-l}+v_{r-l'}\),显然和交叉小于包含矛盾了。

  • 那完事了,\(O(n^2\log)\)?等等,我怎么觉得这个结论很反直觉?

  • \(j-1=0\),则 \(k_{j-1}=0\),从而...从而......\(k=0\)。显然不可能啊摔!

  • 好吧,我们再仔细看看式子:上面的推导只能说明 \(dp_{i-1,l}+v_{r-l}+dp_{i-1,l'}+v_{r'-l'}\leqslant dp_{i-1,l}+v_{r'-l}+dp_{i-1,l'}+v_{r-l'}\),然而这一式子不能推出 \(k_{j-1}\geqslant k_j\),其只是 \(k_{j-1}\geqslant k_j\) 的必要条件。

  • ...好吧。我们回到一开始的性价比,有一个直觉是这样的:只会有一组不选完,毕竟越选越划算,如果靠后的没选完的那一组更划算,则应该都选那组,否则都选这组。

  • 形式化地说,设有两组物品 \(A,B\) 都没选完,不妨认为分别选了 \(k_A,k_B\) 个,则:

    • \(A_{k_A+1}\geqslant B_{k_B}\):放弃取 \(B\),尽量取 \(A\),显然不更劣。

    • \(A_{k_A+1}<B_{k_B}\):这代表着 \(A_{k_A}<B_{k_B}\),于是放弃取 \(A\),尽量取 \(B\),显然更优。

  • OK!那么这样一来,除了我们钦定的那一组之外,都变成 \(01\) 背包了,要么不选要么选完。然而...暴力枚举哪一组不选完?组内的 dp 容易预处理,毕竟就是前缀和;然而即使我处理好前后缀 dp,这一部分的复杂度是 \(O(n^2)\),把三个背包暴力合到一起...虽然合两个其实就够了(第二次不用合,因为只关心 \(dp_K\)),但 \(O(n^2)\)\(n\) 遍,还是暴力复杂度啊。

  • 解法 1:分块。

    • \(B\) 个块,暴力枚举不选完的在哪个块里,合并前后缀 DP 或直接暴力 DP 一遍,反正都是 \(O(n^2)\)

    • 在块内暴力枚举哪个没选完,将其他的物品暴力转到刚才的背包里,\(O(\frac{n}{B}(\frac{n}{B}n))\)

    • 暴力枚举没选完的选了几个,计算对应情况下选 \(K\) 个的最大总价值,\(O(n)\)

    • 故总复杂度为 \(O(B(n^2+\frac{n}{B}(\frac{n^2}{B}+n)))=O(Bn^2+\frac{n^3}{B})=O(n^2(B+\frac{n}{B}))\),取 \(B=\sqrt{n}\),复杂度为 \(O(n^2\sqrt{n})\)

    • 够过了,虽然纸面 \(5\times 10^8\),但背包常数小。

  • 解法 2:分治。

    • 考虑用二分树。怎么到处都是二分树!也许该叫分治树?

    • 令初始区间为 \([1,n]\),先考虑 \(key\leqslant mid\) 的情况,\(key\) 为不选完的一组,此时将 \([mid+1,r]\) 的物品转进背包得到左子区间的背包,回溯时再考虑 \(key>mid\),将 \([l,mid]\) 转进背包。

    • 即我们维护的背包其实是“除了当前区间外的全局背包”。可以看出,同时只需要维护一条链上的 \(\log\) 个背包(转移完毕的就好),每一层都将所有物品转移一次,空间回收的复杂度因为分治树只有 \(O(n)\) 个点所以是 \(O(n^2)\),故总复杂度 \(O(n^2\log)\)

    • 妙哉!

P4095 [HEOI2013] Eden 的新背包问题

  • 题意略。

  • 显然可以和上一题一样建分治树,\(O(nV\log)\) 地解决。我就不写了吧(以前写了个前后缀合并的假做法,时间是假的)...毕竟单调队列优化多重背包码量还是不小的。

posted @ 2023-01-15 10:11  未欣  阅读(84)  评论(0编辑  收藏  举报