一些关于DP的小优化:
前缀和优化(用于 dp[i]=dp[i−k]+v[i]的转移)
bitset优化(01背包(价值能否取到),常数为 ω=1/32)
单调队列优化(求恒长区间最大/小值)
二进制优化(完全背包问题,O(n2 logn) ):P1776
线段树优化:CF1557D
斜率优化:见下文
四边形不等式:见下文
树链剖分(DDP)
斜率优化
本蒟蒻终于被迫学习斜率优化了
这类问题的优化的转移方程是:b(i)=max/min{y(j)−k(i)×x(j)},j<i
以本题为例:
一个朴素的转移方程:
dp[i]=min(dp[j]+(i−j−1+sum[i]−sum[j]−L)2)
其中,sum[i]=∑jk=1c[k]
再合并,令 pre[i]=sum[i]+i
得:
dp[i]=min(dp[j]+(pre[i]−pre[j]−(L+1))2)
强拆!
dp[i]=min(dp[j]+(pre[i]−(L+1))2−2(pre[i]−(L+1))×pre[j]+pre[j]2)
移项:
dp[i]−(pre[i]−(L+1))2=min(dp[j]−2(pre[i]−(L+1))×pre[j]+pre[j]2)
令
bi=dp[i]−(pre[i]−(L+1))2,xj=pre[j],yj=dp[j]+pre[j]2,ki=2(pre[i]−(L+1))
那就变成了 y=kx+b 的转换式 b=y−kx
我们要最小化 b ,就是最小化直线的截距
我们可以将 (xj,yj) 看作平面上的点,现在有一条斜率为 ki 的直线,从下往上移动,碰到的第一个点就是我们的转移决策点(因为要最小化 bi)
实际上,我们只需要维护下凸壳的那些点,而对于本题,显然 ki 随 i 的增大而增大,所以我们只需要用一个单调队列来维护凸壳上的点
借用 OI-Wiki
中的图:

我们令 K(qe−1,qe) 为 (xqe−1,yqe−1) 与 (xqe,yqe) 两点连线的斜率
显然,我们要找的决策点就是凸壳中满足 K(qe−1,qe)≤ki<K(qe,qe+1) 的点 e
因为 ki 是递增的,所以下一次 DP
只需要从 e 开始找决策点,这样均摊下来就是 O(1) 的
又因为 xi=pre[i] 是递增的,所以点 i 一定会加入到凸壳中,我们只需要将 K(qe−1,qe)<=K(qe,(xi,yi)) 的点弹出,再将 i 加入到队列即可
注意:队列的初始状态应该是有一个点 (0,0) ,否则 c1 将永远无法和后面的玩具合并,导致错误!
一般化
但如果我们将上述题目的条件改改,使得 ci 可以为负,那么这时候 ki 和 xi 就不单调递增了,是不是就做不了了???
当然不是啊,不然我提出这个问题干嘛
对于 ki (斜率)不单调的话,我们直接在凸壳上二分,还是找满足原来那个条件的点即可
但如果 xi 不是单调的,我们就很难去更新凸壳了
一种方法就是用平衡树维护凸包,就是找到 xj≤xi≤xj+1 的地方,根据凸包的性质不断向两边删点(或者自己本来就在凸包里面就不用管了)
但用平衡树十分滴复杂,有没有更好写的算法?(其实用 set
是可以实现的)
有!就是我们万能的 CDQ分治
我们假定分治到 (l,r),且 (l,mid) 已经处理完了,现在要对 (mid+1,r) 进行贡献
注意:这时候 (mid+1,r) 还没有分治下去!
我们先将 (l,mid) 的点以 x 为第一关键字, y 为第二关键字排序,然后就直接求一遍凸壳
然后我们再将 (mid+1,r) 按照斜率 k 将编号从小到大排序
这时候我们就可以正常像上面用单调队列跑 DP
了
转移完后,显然 (l,mid) 的决策点已经没有用处了,我们可以直接将其舍弃掉,转到 (mid+1,r) 的分治
整个分治的时间复杂度是 O(nlog2n) 的。
当然,我们也可以用 李超线段树
直接跑 DP
,就是将上面的 k,x,y,b 稍微换一下,每次 DP
在树上查询最大/小值,求完后再更新线段树即可
dp 套 dp
适用范围:要求你构造一些满足特殊要求的序列或字符串,并统计出有多少种不同的方案数
也就是说,这是一种计数DP
的 trick
我们用这道例题讲解一下
我们先考虑求两个序列的 LCS
的方式:
dpi,j=max(dpi−1,j,dpi,j−1,dpi−1,j−1+[ai=bj])
其中,dpi,j 表示 a 串的前 i 位与 b 串的前 j 位的 LCS
显然,一种 dpi 对应着一类的 a 串
而题目又是要我们构造 a 串,我们就考虑记录下每种 a 串的结果 dpi,并以此为外层 DP
的状态进行转移
我们就定义 DPi,j 表示:当 a 串长度为 i 时,它的 dpi 结果为 j 的方案数
但难不成我们要将所有的 dpi 都记录下来,然后再一个个跑吗?
诶,我们这时候就要注意到 k 的大小了,它才 15 啊
是不是又一种直觉,我们可以用状压来记录 dpi ?
事实确实如此!因为我们注意到,dpi,j−dpi,j−1 要不为 0 ,要不为 1
那我们就考虑将 dpi 进行差分后,再用状压记录状态
那我们每次 DP
加入一个新的字符时,就枚举上一个字符的所有状态,解压后再求新的状态,进行转移
题目还有一个不能出现 NOI
串的限制,那我们只需要每次都记录最后几位是否为 N
、NO
或没有即可
四边形不等式
(学完斜率优化才来学决策单调性的屑)
2D1D 区间转移类
在许多的区间DP
中(如石子合并),我们有如下的状态转移方程:
fl,r=min{fl,k+fk+1,r}+wl,r
这显然是 O(n3) 的,但当 n>1e4 时,我们就寄了
但 wl,r 满足一些特殊性质,让我们可以对它进行优化:
当 l≤l′≤r′≤r 时,有 wl′,r′≤wl,r 成立,则函数 w 对于区间包含具有单调性
当 l1≤l2≤r1≤r2 时,有 wl1,r1+wl2,r2≤wl1,r2+wl2,r1 成立,则称函数 w 满足四边形不等式(简记为“交叉小于包含”)
但我们需要的是 fl,r 满足四边形不等式,才能进行优化
若 wl,r 满足上面的两个性质,则 fl,r 也满足四边形不等式
令 u 为 fl1,r2 的最优决策点,v 为 fl2,r1 的最优决策点
(由于当 l2=r1 时 v 是没有意义的,所以我们需要分开讨论)
显然,当 l1=l2 或 r1=r2 时,不等式相等,成立
下面我们用归纳法
证明区间长度为 r2−l1 满足四边形不等式
-
当 l1<l2=r1<r2 时
A. 若 u<r1,有 fl1,r1≤fl1,u+fu+1,r1+wl1,r1,由归纳法得 fu+1,r1+fl2,r2≤fu+1,r2+fl2,r1,两式相加,有:
fl1,r1+fl2,r2≤fl1,u+fu+1,r2+fl2,r1+wl1,r1
又因为 wl1,r1≤wl1,r2,fl1,r2=fl1,u+fu+1,r2+wl1,r2
所以 fl1,r1+fl2,r2≤fl1,r2+fl2,r1
B. 若 u≥r1,有 fl2,r2≤fl2,u+fu+1,r2+wl2,r2,由归纳法得 fl1,r1+fl2,u≤fl1,u+fl2,r1,两式相加,有:
fl1,r1+fl2,r2≤fl1,u+fu+1,r2+fl2,r1+wl2,r2
又因为 wl2,r2≤wl1,r2,fl1,r2=fl1,u+fu+1,r2+wl1,r2
所以 fl1,r1+fl2,r2≤fl1,r2+fl2,r1
-
当 l1<l2<r1<r2 时
A. 若 u≤v,则 l1≤u<r1, l2≤v<r2(r1),有
fl1,r1≤fl1,u+fu+1,r1+wl1,r1fl2,r2≤fl2,v+fv+1,r2+wl2,r2
由 u+1≤v+1≤r1<r2 and 归纳法,有 fu+1,r1+fv+1,r2≤fu+1,r2+fv+1,r1,前两个不等式相加,将第三个不等式代入,得
fl1,r1+fl2,r2≤fl1,u+fl2,v+fu+1,r1+fv+1,r2+wl1,r1+wl2,r2≤fl1,r2+fl2,r1
B. 若 u>v,则 l2≤u<r2, l1(l2)≤v<r1,有
fl2,r2≤fl2,u+fu+1,r2+wl2,r2fl1,r1≤fl1,v+fv+1,r1+wl1,r1
由l1<l2≤v<u and 归纳法,有 fl1,v+fl2,u≤fl1,u+fl2,v,前两个不等式相加,将第三个不等式代入,得
fl1,r1+fl2,r2≤fl1,v+fl2,u+fv+1,r1+fu+1,r2+wl1,r1+wl2,r2≤fl1,r2+fl2,r1
综上所述,fl1,r1+fl2,r2≤fl1,r2+fl2,r1
记 tl,r 为 fl,r 的最优决策点,则有:
tl,r−1≤tl,r≤tl+1,r
证明:设 L=tl,r−1,M=tl,r,R=tl+1,r
-
若 L>M
根据 M+1<L+1≤r−1<r, 有 fM+1,r−1+fL+1,r≤fM+1,r+fL+1,r−1
又根据 L 为 fl,r−1 的最优决策点,得 fl,L+fL+1,r−1≤fl,M+fM+1,r−1
两式相加,得 fl,L+fL+1,r≤fl,M+fM+1,r
这说明 L 比 M 对于 fl,r 更优,显然矛盾,所以 L≤M
-
若 M>R
根据 l<l+1≤R<M, 有 fl,R+fl+1,M≤fl,M+fl+1,R
又根据 R 为 fl+1,r 的最优决策点,得 fl+1,R+fR+1,r≤fl+1,M+fM+1,r
两式相加,得 fl,R+fR+1,r≤fl,M+fM+1,r
这说明 R 比 M 对于 fl,r 更优,显然矛盾,所以 M≤R
通过上述的证明,我们在DP
的过程中就可以减少枚举决策点的次数,复杂度能够优化到:
∑1≤l<r≤ntr,i+1−tr−1,i=n∑i=1ti,n−t1,i≤n2
fl,r=min{fl−1,k}+wk,r
其中 1≤l≤n, 1≤j≤m,所以直接做的复杂度是 O(nm2) 的
但实际上,如果 wl,r 能满足区间包含单调性
和四边形不等式
,fl,r 也一样满足四边形不等式
,有 tl,r−1≤tl,r≤tl+1,r
由于是逐层转移,我们考虑对第 i 层进行分治
我们设置状态 (l,r,tl,tr),表示分治到 [l,r],fi,mid 的最优决策点在 [tl,tr]
我们暴力枚举 fi,mid 的决策点,找到最优的决策点 tmid,再向下分治 (l,mid,tl,tmid), (mid+1,r,tmid,tr)
时间复杂度就优化到 O(nm log m)
也就是当 wk,r 不能在 O(1) 下计算
我们可以采用莫队双指针移动的方法
也就是在暴力求 mid 的决策点时,像莫队那样移动到需要的区间
这样一看,似乎复杂度假掉了
但实际上,这还是 O(nmlogn) 的
因为当我们枚举到 l,r,tl,tr 时,双指针一定在 tl,tr 内
因为右指针不动,只有左指针移动 O(mid−l) 次
递归到左儿子的时候暴力移动到 tl,tmid,给右儿子移动到 tmid,tr,这部分也不超过 r−l
因此平衡到与分治一样的复杂度
1D1D 转移类
fr=min{fl+wl,r}
如果 wl,r 满足四边形不等式
,令 tr 为 fr 的最优决策点,则有 r1<r2,tr1≤tr2
证明:令 L=tr1, R=tr2
-
若 L>R ,则 R<L<r1<r2,由四边形不等式有 wR,r1+wL,r2≤wR,r2+wL,r1
-
因为 L 是最优决策点,所以有 fL+wL,r1≤fR+wR,r1
-
两不等式相加,得 fL+wL,r2≤fR+wR,r2
-
这显然与 R 是 fr2 的最优决策点相矛盾,所以 L≤R
但这时我们仅仅确定了下界,最坏情况下仍是 O(n2) 的
我们考虑使用单调队列
,里面记录的是决策点,每个决策点能够转移到的区间为 [Lq[i],Lq[i+1]−1]
当我们要转移到 fi 时,我们就取出队头,如果他的转移区间 [Lq[he],Lq[he+1]−1] 不包含 i,也就是 Lq[he+1]≤i,我们就将其弹出,最后没被弹出的队头就是最优决策点
那我们如何更新队列呢?我们就每次取出队尾,比较一下从 i 转移到 Lq[ta] 是否比从 qta 转移到 Lq[ta] 更优,如果是,代表 i 所能转移到的区间已经覆盖了 tta 了,根据决策单调性,我们就将队尾弹出
但这还没完,因为 i 虽然没有覆盖某个队尾,但它可能覆盖了其中一小部分,因此我们要对队尾所覆盖的区间 [Lq[ta],N] 进行二分,找出第一个点 k,使得 i 转移到 k 比 Lq[ta] 转移到 k 更优,作为 i 覆盖区间的起点
时间复杂度则为 O(n log n)
快速判断
对于1D1D
:详见大佬FlashHu的博客
简而言之,对于每个决策函数 fj(i)(也就是转移中只和 j 有关的变量),如果任意两个函数只有一个交点:直线或形状相同(可以通过平移转换),其导函数单调,就有可能是决策单调
对于2D1D
:证明 wl,r+1+wl+1,r≤wl,r+wl+1.r+1,也就是证明 wl,r 满足四边形不等式,那么 fl,r 也一般会满足四边形不等式(毕竟没人出个决策单调的诈骗题吧......)
SOS DP
问题引入:求
F[S]=∑i∈SA[i]
我们有 O(4n) 的暴力,有 O(3n) 的子集枚举,但一旦 n 较大,我们都得凉凉
其实我们有一个 O(n2n) 的做法
我们令 dp[S][i]=∑j∈S and j⊕S<2i+1A[j]
考虑如何转移
dp[S][i]{dp[S][i−1] (S & 2i=0)dp[S][i−1]+dp[S⊕2i][i−1] (S & 2i=2i)
最后我们输出 dp[S][n] 即可
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】