决策单调性优化 DP

决策单调性优化 DP

这里面学问很深啊。优化方式也多种多样。

总的来说,对于一类形如 fi=minfj+w(j,i) 的转移方程,设 pi 为使 fj+w(j,i) 取到最小值的点,那么如果 pi 单调递增,我们就可以使用决策单调性优化 DP。

定理

这里给出一个定理:pi 单调递增,当且仅当 w 满足四边形不等式,即

(1)w(i,j)+w(i+1,j+1)w(i,j+1)+w(i+1,j)

这个式子有更一般(但完全等价)的形式,即

(2)abcd,w(a,c)+w(b,d)w(a,d)+w(b,c)

更一般地,如果转移方程形如 fi=maxfj+w(j,i),那么将 (2) 式若将不等号反向后成立,那么该转移同样满足决策单调性。证明基本一样。

不难用归纳法从 (1) 推出 (2),在 (2) 中令 a=i,b=i+1,c=j,d=j+1 即得 (1)

略证:四边形不等式即 w(i,j)w(i,j+1)w(i+1,j)w(i+1,j+1)

从这个式子可以看出来,四边形不等式实际上体现了某种意义上的凸性质。

因此大多数和「次幂」(如平方,根号)有关的式子都可以猜一手决策单调性。毕竟幂函数总是凸的。

因此,考虑 fi 的决策点 pi,由 pi 的最优性,对于任意的 j<pi,均有

(3)fj+w(j,i)fpi+w(pi,i)

我们证明:当 i 变为 i+1 时仍有 fj+w(j,i+1)fpi+w(pi,i+1)。下面简记 ppi

由于 w 满足四边形不等式,因此

w(j,i)+w(p,i+1)w(p,i)+w(j,i+1)

这里 a,b,c,d 分别为 a=j,b=p,c=i,d=i+1

(4)w(j,i)w(j,i+1)w(p,i)w(p,i+1)

(3)+(4) 即得 fj+w(j,i+1)fpi+w(pi,i+1)。这就完成了证明。

二分队列

现在我们知道 pi 单调递增,第一个想法是在转移时从 pi1i1 枚举 j 尝试转移,但是这样复杂度也不对。

我们考虑直接维护 pi 这个序列,一开始将 pi 全部设置为 1,也就是先让所有 fi 都从 1 转移。

我们的算法可以保证在计算到 i 时,pi 恰好就是 fi 的最优决策点。

在计算到 fi 时,首先由 pi 直接计算出 fi 的值,接下来我们将根据 fi 的值来更新后面的决策点。

具体来说,由决策单调性我们可以知道,一旦某个地方满足 pj=i,那么后面的 pj+1n 都至少是 i

而当前我们只考虑到 i,也就是决策集合只有 1,2,,i,因此实际上只需要找到这个位置 j 满足

  • fi 恰好是 fj 的最优决策点,但是 fj1 的最优决策点在 i 之前

然后把 pjn 全都赋值为 i 即可。找到这样的 j 可以使用二分。根据决策单调性,这样的 j 应当满足 p 数组中目前存储的决策点中,j 之前的决策都比 i 好,j 之后的决策都比 i 差,二分出这个位置即可。

现在得到这个位置之后,我们需要对 j 后面的位置进行整体赋值。你说我会用线段树维护序列,当然可以,不过这样做复杂度似乎要 2log,而用下面的方式可以做到 1log

其实说出来也没什么,把序列划分成若干极长连续段,满足每个连续段中 p 的值都相同。接下来二分完成后只需要修改 O(1) 个连续段,删除若干连续段,并插入一个连续段即可。这其实就是所谓「珂朵莉树」。

分治优化

这一种优化方式仅限 gf 的情形,也就是给定 g,我们需要算出 fi=minj<igj+w(j,i) 的情形。

我们定义 solve(l,r,pl,pr) 表示需要计算出 f[lr] 的最优决策点,并且已经确定了每个决策点都在 [pl,pr] 之内。考虑找到区间中点 m=(l+r)/2,然后暴力计算 fm 的最优决策点 pm

由决策单调性我们知道 [l,m] 中的决策点都在 [pl,pm] 中,[m+1,r] 的决策点都在 [pm,pr] 中,因此可以递归进 solve(l,m1,pl,pm)(m+1,r,pm,pr)

复杂度如何呢?画出分治树,分治树共 O(logn) 层,在每一层中,所有的 [pl,pr] 并起来恰好是 [1,n],因此总的枚举次数不超过 nlogn。如果计算 w 的时间复杂度是 O(f(n)),那么总的时间复杂度是 O(nlogn×f(n))

你或许已经发现,如果要算 ff 的转移,这种方法需要在计算 pm 时已知前面的所有 f 值。

而这是不可能的,因此这种方法只适用于 gf 的转移,方法一则同时适用于 ffgf

但方法一也有缺点,下面我们就会说明。

大多数情况下 O(f(n))=O(1),不过也存在少数 f 不好计算的情况。

若贡献难以在常数时间内计算

对于这类贡献,虽然 w(l,r) 难以 O(1)O(logn) 计算,但 w 如果满足

  • 在已知 w(l,r) 的情况下,我们可以快速算出 w(l,r+1) 以及 w(l1,r)

那么同样可以使用分治法在 O(nlogn×) 的时间复杂度内完成转移,其中 部分是通过 w(l,r)w(l,r+1)w(l1,r) 的复杂度。

解决方法很暴力:我们在全局维护两个指针 L,R,每次需要计算 w(l,r) 时,直接暴力将 L,R 移动至需要查询的区间。这看起来非常暴力,但是我们可以证明:

  • 按照正常的 DFS 序遍历分治树,指针的移动次数不会超过 O(nlogn)

我们把左右端点分开考虑。

对于右端点,由于它总是被设为 m=(l+r)/2 后不动,接下来递归进 solve(l,m1,)solve(m+1,r,),因此指针总是从区间 [l,r] 的某个端点移动到中点处,次数不超过 O(rl),总的移动次数自然不超过 O(nlogn)

对于左端点,它在移动完后总是等于 min(m1,pr),类似右端点可以证明左端点的移动次数是 O(prpl) 的。因此,总的移动次数同样是 O(nlogn)

这就是分治法的优点所在,可以发现二分法是无法处理这样的贡献的。

有些文章把这种方法称为「整体二分」,我认为也有一定道理

对于 ff 类,且贡献难以计算的转移方程,我暂时没有好的解决办法,有鸽鸽教教我吗/kel

当决策值单峰

这里单峰(单谷)指的是,设 fi 的最优决策点为 p,则:

  • p 之前的决策值 fj+w(j,i)j 增大单调递减,p 之后的决策值单调增。

这样,我们就可以直接维护 fi 的最优决策点 pi,并在计算 fi+1 时维护指针 jpi 开始往后跳,一旦发现 fj+w(j,i)<fj+1+w(j+1,i) 就说明找到了峰值,可以直接用 fj+w(j,i) 更新 fi

由单峰的性质可以得到这样做的正确性。算法的时间复杂度是优秀的 O(n)

不难发现这同样适用于贡献难算但可以快速移动端点的情形。

二分栈

例题

POI2011 Lightning Conductor

很板的题,分 j<ij>i 讨论,看到 ij 很容易猜到凸性质,因此具有决策单调性。两种优化方式均可。

NOI2009 诗人小 G

同样是幂函数,容易猜到凸性质。不过这次只能用第一种优化方式了。

CF868F Yet Another Minimization Problem

k 层转移,贡献不好计算但可以快速移动区间端点,使用分治法,复杂度 O(nklogn)。代码巨好写

Luogu5774 CmdOI2019 任务分配问题

区间逆序对看上去也很有次幂的味道,我们猜它满足四边形不等式。

略证:四边形不等式即 w(l,r+1)w(l,r)w(l+1,r+1)w(l+1,r)

我们发现左边恰好是 [l,r]<ar+1 的元素个数,右边恰好是 [l+1,r]<ar+1 的元素个数

显然左边不会比右边小,这就完成了证明。类似上题,用树状数组维护区间转移即可做到 O(nklog2n)

posted @   云浅知处  阅读(117)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示