【学习笔记】DP 优化 5:wqs 二分优化 DP

Page Views Count

概述#

wqs 二分是一种优化带有数量限制的最优化问题的方式(即题目限制最多/最少/恰好选择 m 个物品时的最大/小值),要求关于数量的函数具有凸性。以最小值为例,要求函数是下凸的。

算法思想#

由于状态数至少 O(nm),在朴素 DP 的基础上进行优化,时间复杂度也不会低于 O(nm),因此要想办法解除 m 的限制。

设函数 Fi 表示选择 i 个物品的最小值,考虑增加一个附加权值 k,每选择一个物品需要增加 k 的代价,令 Gi=Fi+ki,那么 Gi 也是下凸的,求出此时 Gi 的最小值对应位置 (p,Gp),这实际上等价于用斜率为 k 的直线去切 Fi 构成的凸包,对应的截距就是 Gp

不难发现,由于凸函数的斜率具有单调性,可以二分 k 来找到使 (m,Gm) 恰好为最小值的情况,这样就能将数量放入转移方程中,从而忽略严格的数量限制。

实现细节#

存在一个可能的问题:Fi 可能出现多点共线的情况,即 (m,Fm) 可能永远无法被切到。

(m,Fm) 左右的斜率都为 K,那么二分过程中,一定存在斜率为 K 的时刻,此时整个线段的截距都相等,自然可以计算。

同时在二分过程中,如果当前的 k 满足条件,那么直接更新答案为 Gpkm,注意不是 Gpkp,也不是取 min/max

二分之后,内层的处理一般是使用较为朴素的 DP 优化手段,例如斜率优化、决策单调性分治以及二分队列。

内层处理的 DP 可能存在值相同的情况,此时可以选择数量尽量多的方案,这样如果此时的 pm,则可能是合法答案,可以更新,否则不是。

函数凸性的证明#

在大多数题目中,Fi 的凸性都是通过感性理解和打表来验证的,但也存在一部分题目具有良好的性质。

对于将 [1,n] 划分为有数量限制的若干段求最值的区间划分问题,转移方程形如:

fk,i=minj=1i{fk1,j1+w(j,i)}

w(j,i) 满足四边形不等式,则 Fi=fi,n 是凸函数。

证明从凸函数差分数组单调性入手,即证明 FiFi1Fi+1Fi2FiFi1+Fi+1

考虑 Fi1 对应的区间划分 [a1,d1],[a2,d2][ai1,di1] 以及 Fi+1 对应的区间划分 [b1,c1],[b2,c2][bi+1,ci+1],找到最小的 j 使得 cj+1dj,同时满足 bj+1>aj,即 aj<bj+1cj+1dj,此时将 [aj,dj],[bj+1,cj+1] 之后的区间交换,这两个区间交换右端点,即 [a1,d1],[a2,d2][aj,cj+1],[bj+2,cj+2][bi+1,ci+1] 以及 [b1,c1],[b2,c2][bj+1,dj],[aj+1,dj+1][ai1,di1]

这样两个划分大小都是 i。设交换后两个方案的权值和 S,由于 Fi 是最优方案,有 2FiS,同时根据四边形不等式,交换后的 w(aj,cj+1)+w(bj+1,dj)w(aj,dj)+w(bj+1,cj+1),那么 2FiSFi1+Fi+1,凸性得证。

满足四边形不等式的基础上,还可以使用二分队列来优化,一举两得。

例题#

Luogu-P2619 国家集训队 Tree I#

不是 DP 题目,但是是比较经典的 wqs 二分。

Fi 为选择 i 条白色边的最小生成树,数量尽量多对应排序时白边优先。

Luogu-P4983 忘情#

整理一下发现就是 (xi+1)2,满足四边形不等式所以是凸的,可以 wqs 二分。

内层用斜率优化或者二分队列均可。

AtCoder-JOISP2023_G ビーバーの合唱#

首先通过调整,使得第 iA 在第 iB 之前,容易发现对于所有方案,这样的调整都是要进行的。

之后大致考虑一个 DP,fk,i 表示当前把前 iAB 划分成 k 段的最小操作次数。

转移需要考虑贡献函数 w(j,i) 表示将第 [j+1,i]AB 调整成所有 A 都在 B 前的最小操作次数。由于现在保证第 iA 一定在第 B 前,那么将第 j+1A 到第 iB 的部分拿出来,发现可以分成五部分:一些排名在 [j+1,i] 内的 A、一些排名 jB、一些 AB、一些排名 >iA 以及一些排名在 [j+1,i] 内的 B。发现实际上操作只在第三部分进行,那么每个 A 需要被操作的次数等于前面 B 的个数。

prei 表示第 iA 前面 B 的个数,那么得到贡献函数 w(j,i)=p=j+1imax(prepj,0),容易证明 w(j,i) 满足四边形不等式,可以 wqs 二分优化。

考虑如何优化内层 DP,首先是去掉取 max,设 posi 表示第一个 preiA,得到 w(j,i)=p=posjiprepj。记 prei 的前缀和 sumi,就化简成了 w(j,i)=sumisumposj1+(iposj+1)×j,可以斜率优化。

同样存在 posj>i 的情况不能拆成前缀和,这时贡献函数为 0,而由于 posj 单调,在斜率优化时可以等到 posji 出现再把 j 加入凸包,同时还要维护没有加入的 jfj 的最小值,可以单调队列。这样内层 DP 就做到线性。

参考资料#

作者:SoyTony

出处:https://www.cnblogs.com/SoyTony/p/Learning_Notes_about_DP_Optmization_5.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   SoyTony  阅读(182)  评论(2编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
more_horiz
keyboard_arrow_up light_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示