决策单调性一般可用观察法/分析四边形不等式得出,这里主要介绍四边形不等式。
在这里我们只讨论代价为二元函数 w(l,r) 的 dp。
Part 1 定义 & 性质
1.1 dp 维数定义
描述 dp 的时间复杂度时,往往会用 xD/yD 这样的说法,其中 x 为 状态数logn,y 为 单次转移复杂度logn。
例如 fl,r=k=l+1∑rfl,k−1+fk,r 是 2D/1D 的 dp。
1.2 决策单调性
设 dp 的状态集合为 S,状态 u 的最优决策点为 opt(u)。
若 ∀i,j∈S,i<j 都有 opt(i)≤opt(j),则称该 dp 满足决策单调性。
1.3 区间包含单调性和四边形不等式
这两个东西都是定义在二元函数 f(l,r) 上的。
1.3.1 区间包含单调性
若 ∀l≤l′≤r′≤r,都有 f(l′,r′)≤f(l,r),则称 f 满足区间包含单调性。
1.3.2 四边形不等式
若 ∀l≤l′≤r′≤r,都有 f(l,r′)+f(l′,r)≤f(l,r)+f(l′,r′),则称 f 满足四边形不等式。
即相交小于包含。
1.3.3 一些帮助证明的性质
- 若 w(l+1,r)≤w(l,r) 且 w(l,r−1)≤w(l,r),则可以归纳证明 w(l,r) 满足区间包含单调性;
- 若 w(l+1,r)+w(l,r−1)≤w(l,r)+w(l+1,r−1),则可以归纳证明 w(l,r) 满足四边形不等式;
- 线性性:若 f(l,r) 与 g(l,r) 均满足区间包含单调性 / 四边形不等式,则 ∀c1,c2≥0,c1×f(l,r)+c2×g(l,r) 也满足区间包含单调性 / 四边形不等式;
- 若 w(l,r)=f(r)−g(l):
- w(l,r) 满足四边形恒等式(≤ 恒取 =);
- 若 f,g 均单调不增,则 w(l,r) 还满足区间包含单调性;
- 若 f(x) 为下凸函数(导数不降),w(l,r) 满足区间包含单调性和四边形不等式:
- f(w(l,r)) 满足四边形不等式;
- 若 f(x) 单调不降,则 f(w(l,r)) 还满足区间包含单调性;
证明
(2):
w(l+1,r)+w(l,r−1)≤w(l,r)+w(l+1,r−1)w(l+1,r−1)+w(l,r−2)≤w(l,r−1)+w(l+1,r−2)w(l+1,r)+w(l,r−1)+w(l+1,r−1)+w(l,r−2)≤w(l,r)+w(l+1,r−1)+w(l,r−1)+w(l+1,r−2)w(l+1,r)+w(l,r−2)≤w(l,r)+w(l+1,r−2)(1)(2)(1)+(2)
(5).1:不会证,感性理解一下:
- 满足区间包含单调性:更长的区间 w(l,r) 更大;
- 下凸函数:更大的 w(l,r) 增长得更快;
- 原本就满足四边形不等式:相交总和更小;
Part 2 应用
这里默认代价函数为二元函数 w(l,r),且该函数计算时间复杂度为 O(1)。
2.1 优化 1D/1D dp
若 w(l,r) 满足四边形不等式,则如下 1D/1D dp 存在决策单调性:
fi=j=0mini−1{w(j+1,i)}朴素形fi=j=0mini−1{fj+w(j+1,i)}区间划分形
即 ∀i<j,opt(i)≤opt(j)。
证明
先证明第二个:
解释:若出现上面的情况,则可以交换变成下面的情况,fi+fj 变小,与 fi 和 fj 均为最小值相悖。
第一个只不过是把黑色部分去掉了。
那么就可以分治或者在队列上二分来快速转移,时间复杂度 O(nlogn)。
2.1.1 分治优化转移
该方法仅适用于转移不依赖之前状态的情况(朴素形),在这种情况下,仅需求出 opt(i) 即可得出 fi。
考虑分治,令 mid=⌊2n⌋,先求出 k=opt(mid),接下来:
- 对于 i∈[1,mid−1],opt(i)≤k;
- 对于 i∈[mid+1,n],opt(i)≥k;
那么在分治的时候记录 opt(i) 的上下界即可。这样分治树的高度为 O(logn),每一层每一个转移点只会被遍历到最多两次,总时间复杂度即为 O(nlogn)。
示例代码
void dfs(int opt[],int(*calw)(int,int),int l,int r,int kl,int kr)
{
if(l>r) return;
int mid=l+r>>1,k=kl;
for(int i=kl;i<=kr&&i<=mid;i++)
{
if(calw(i,mid)<calw(k,mid)) k=i;
}
opt[mid]=k;
dfs(opt,calw,l,mid-1,kl,k);
dfs(opt,calw,mid+1,r,k,kr);
}
例题:P3515 [POI2011] Lightning Conductor
题解
考虑拆成两半求解,先求满足 [1,i] 的 p,再求满足 [i,n] 的 p,取 max。
设 fi 为前一半的 p,有:
fi=j<imax{aj+i−j−ai}=−j<imin{ai−aj−i−j}
由于 w1(j,i)=−i−j 和 w2(j,i)=ai−aj 都满足四边形不等式,所以 w(j,i)=w1(j,i)+w2(j,i) 也满足四边形不等式。
那么直接分治优化转移即可,时间复杂度 O(nlogn)。
记得寻找 opt(i) 时代价不能上取整,要最后再上取整。
参考代码
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
typedef long double db;
const int S=500005;
int n,a[S];
int opt1[S],opt2[S];
int ans[S];
inline db calw(int l,int r)
{
return a[r]-a[l]-sqrt((db)(r-l));
}
void dfs(int opt[],db(*calw)(int,int),int l,int r,int kl,int kr)
{
if(l>r) return;
int mid=l+r>>1,k=kl;
for(int i=kl;i<=kr&&i<=mid;i++)
{
if(calw(i,mid)<calw(k,mid)) k=i;
}
opt[mid]=k;
dfs(opt,calw,l,mid-1,kl,k);
dfs(opt,calw,mid+1,r,k,kr);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
dfs(opt1,calw,1,n,1,n);
for(int i=1;i<=n;i++) ans[i]=ceil(-calw(opt1[i],i));
for(int i=1;i<=n/2;i++) swap(a[i],a[n-i+1]);
dfs(opt2,calw,1,n,1,n);
for(int i=1;i<=n;i++) ans[n-i+1]=max(ans[n-i+1],(int)ceil(-calw(opt2[i],i)));
for(int i=1;i<=n;i++) printf("%d\n",ans[i]);
return 0;
}
练习:Loj #6039. 「雅礼集训 2017 Day5」珠宝 /「NAIPC2016」Jewel Thief
2.1.2 二分队列优化转移
该方法适用于转移依赖之前状态的情况(区间划分形)。
观察到对于特定的 j,opt(i)=j 的 i 肯定形成一个区间。
那么不妨用单调队列维护 j 和其对应的区间 [lj,rj],队头为 lj 最小的,队尾为 lj 最大的。
每次转移到新的 i 时:
- 先把队头 rj<i 的决策点弹掉,得到 opt(i),从而得到 fi,令队头 lj=i+1;
- 然后对于队尾决策点 j,若 fi+w(i+1,lj)<fj+w(j+1,lj) 则弹掉队尾;
- 若队列为空,加入决策 i,令 li=i+1,ri=n;
- 否则二分找到分界点再加入决策 i;
这样每个决策点最多只会入队一次,所以总时间复杂度为均摊 O(nlogn)。
参考代码
lb[0]=1,rb[0]=n;
hed=1,til=0;
que[++til]=0;
f[0]=0;
for(int i=1;i<=n;i++)
{
while(rb[que[hed]]<i) hed++;
int opti=que[hed];
f[i]=f[opti]+calw(opti+1,i);
if(rb[opti]==i) hed++;
else lb[opti]=i+1;
while(hed<=til&&
f[i]+calw(i+1,lb[que[til]])
<
f[que[til]]+calw(que[til]+1,lb[que[til]])
) til--;
if(hed>til)
{
if(i<n)
{
lb[i]=i+1,rb[i]=n;
que[++til]=i;
}
}
else
{
int j=que[til];
int l=lb[j],r=rb[j],p=lb[j];
while(l<=r)
{
int mid=l+r>>1;
if(f[j]+calw(j+1,mid)<f[i]+calw(i+1,mid)) p=mid,l=mid+1;
else r=mid-1;
}
rb[j]=p;
if(p<n)
{
lb[i]=p+1,rb[i]=n;
que[++til]=i;
}
}
}
例题:P3195 [HNOI2008] 玩具装箱
题解
设 fi 表示 [1,i] 的代价,那么有转移:
fi=0≤j<imin{fj+w(j+1,i)}
其中 w(l,r)=(r−l+l≤k≤r∑Ck−L)2。
设 Si=1≤j≤i∑Cj,那么 w(l,r)=(r−l+Sr−Sl−1−L)2。
显然 r−l+Sr−Sl−1−L 满足区间包含单调性和四边形不等式,由于 f(x)=x2 是下凸函数,所以 w(l,r) 满足四边形不等式。
那么直接二分队列优化转移即可,时间复杂度 O(nlogn)。
参考代码
#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;
const int S=50005;
int n,L;
ll a[S];
int lb[S],rb[S];
int hed,til,que[S];
ll f[S];
inline ll calw(int l,int r)
{
ll x=r-l+a[r]-a[l-1];
return (x-L)*(x-L);
}
int main()
{
scanf("%d%d",&n,&L);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]),a[i]+=a[i-1];
lb[0]=1,rb[0]=n;
hed=1,til=0;
que[++til]=0;
f[0]=0;
for(int i=1;i<=n;i++)
{
while(rb[que[hed]]<i) hed++;
int opti=que[hed];
f[i]=f[opti]+calw(opti+1,i);
if(rb[opti]==i) hed++;
else lb[opti]=i+1;
while(hed<=til&&
f[i]+calw(i+1,lb[que[til]])
<
f[que[til]]+calw(que[til]+1,lb[que[til]])
) til--;
if(hed>til)
{
if(i<n)
{
lb[i]=i+1,rb[i]=n;
que[++til]=i;
}
}
else
{
int j=que[til];
int l=lb[j],r=rb[j],p=lb[j];
while(l<=r)
{
int mid=l+r>>1;
if(f[j]+calw(j+1,mid)<f[i]+calw(i+1,mid)) p=mid,l=mid+1;
else r=mid-1;
}
rb[j]=p;
if(p<n)
{
lb[i]=p+1,rb[i]=n;
que[++til]=i;
}
}
}
printf("%lld\n",f[n]);
return 0;
}
2.2 优化 2D/1D dp
2.2.1 恰好 k 段的区间划分形
若 w(l,r) 满足四边形不等式,则如下 2D/1D dp 存在决策单调性:
fi,k=0≤j<imin{fj,k−1+w(j+1,i)}
即满足 opt(i,k−1)≤opt(i,k)≤opt(i+1,k)。
证明
opt(i,k)≤opt(i+1,k) 套用 1D/1D 的区间划分形 dp 的证明方法即可,仅需证明 opt(i,k−1)≤opt(i,k)。
不会证,感性理解一下。
并且这类问题有个神奇的性质(同样不会证):
fi,k 是关于 k 的下凸函数。
感性理解一下就是刚开始分的越多越好,超过一个临界点分多点反而不好了。
也就是说,这类问题都可以 wqs 二分。
2.2.2 区间合并形
若 w(l,r) 满足四边形不等式和区间包含单调性,则如下 2D/1D dp 存在决策单调性:
fl,r=l≤k<rmin{fl,k+fk+1,r}+w(l,r)
即满足 opt(l,r−1)≤opt(l,r)≤opt(l+1,r),且 fl,r 也满足四边形不等式。
并且若 w(l,r) 和 fl,r 均非负,fl,r 也满足区间包含单调性。
证明
四边形不等式和区间包含单调性的证明:
-
四边形不等式:
考虑归纳,l≥r−2 时显然成立。
仅需证明 fl,r−1+fl+1,r≤fl,r+fl+1,r−1。
不妨设 opt(l,r)=k。
-
k=l 或 k=r−1:
这里假设 k=r−1,另一种情况同理。
有:
fl,r+fl+1,r−1=fl,k+fk+1,r+w(l,r)+fl+1,r−1=fl,r−1+fr,r+w(l,r)+fl+1,r−1
由于 w(l,r) 满足区间包含单调性,所以 w(l,r−1)≤w(l,r),那么有:
fl,r+fl+1,r−1≥fl,r−1+fr,r+w(l,r−1)+fl+1,r−1≥fl,r−1+fl+1,r
最后一步是根据 dp 转移式得到的。
-
l<k<r−1:
此时设 opt(l+1,r−1)=p,不妨假设 k≤p,k>p 同理:
fl,r+fl+1,r−1=fl,k+fk+1,r+w(l,r)+fl+1,p+fp+1,r−1+w(l+1,r−1)≥fk+1,r−1+fp+1,r+fl,k+fl+1,p+w(l,r)+w(l+1,r−1)≥fk+1,r−1+fp+1,r+fl,k+fl+1,p+w(l,r−1)+w(l+1,r)≥fl,r−1+fl+1,r
其中:
- 第二个不等式是因为根据归纳假设,有 fk+1,r−1+fp+1,r≤fk+1,r+fp+1,r−1;
- 第三个不等式是因为 w(l,r) 满足四边形不等式;
- 第四个不等式是根据 dp 转移式得到的;
-
区间包含单调性:
证明起来比较简单,依旧考虑归纳,l=r 时显然成立。
仅需证明 fl,r−1≤fl,r 和 fl+1,r≤fl,r。
这里证明 fl,r−1≤fl,r,另一个的证明是一样的。
设 opt(l,r)=k。
-
l≤k<r−1:
有:
fl,r=fl,k+fk+1,r+w(l,r)≥fl,k+fk+1,r−1+w(l,r−1)≥fl,r−1
其中:
- 第二个不等式是因为 w(l,r) 满足区间包含单调性,并且根据归纳假设,有 fk+1,r−1≤fk,r;
- 第三个不等式是根据 dp 转移式得到的;
-
k=r−1:
设 opt(l,r−1)=p,有:
fl,r=fl,r−1+fr,r+w(l,r)
由于 w(l,r) 非负,fr,r 也非负,所以 fl,r≥fl,r−1。
决策单调性的证明:
根据决策单调性,我们在 dp 的时候就可以记录 opt(l,r),转移的时候先枚举区间长度,枚举 k 只在 opt(l,r−1) 和 opt(l+1,r) 之间枚举。这样长度相同的区间的枚举 k 的时间复杂度总和是 O(n) 的,那么整体时间复杂度也就是 O(n2) 的了。
例题:石子合并(加强版)
有 n 堆石子排成一个环,第 i 堆石子有 ai 个。
可以把相邻的两堆石子合并为一堆,合并的代价为两堆石子的个数之和,求把所有石子合并成一堆的最小代价和最大代价。
1≤n≤2500。
题解
先段环为链,设 si=j=1∑iaj,fl,r 为把 a[l,r] 合并为一堆的最小代价,那么有转移:
fl,r=l≤k<rmin{fl,k+fk+1,r}+sr−sl−1
显然由于 ai 非负,所以 w(l,r)=sr−sl−1 满足区间包含单调性和四边形不等式,那么 fl,r 满足决策单调性,所以可以直接优化到 O(n2)。
2.3 更多练习
Upd 20250206 更具有启发性的严格定义
关于单调性的定义
启发:对于这种二维的事物,不妨考虑矩阵/二维平面。
仅考虑最小化的情况,最大化情况同理。
关于最小值的位置,若有多个则默认为第一个。
- 单调矩阵 An×m:设 mini 为第 i 行的最小值的位置,则 ∀i1<i2,有 mini1≤mini2;
- 完全单调矩阵 Cn×m:对于其所有子矩阵 A(不一定要连续),A 都是单调矩阵;
- 蒙日矩阵 Mn×m:对于任意一个 2×2 的子矩阵 [acbd](不一定要连续),其满足 a+d≤b+c(相交小于包含);
一些性质
单调矩阵一般都是完全单调矩阵,而大部分完全单调矩阵都是蒙日矩阵。
- 根据定义,不难发现仅需 check 2×2 的子矩阵即可得知一个矩阵是否完全单调,相当于对于所有 2×2 的子矩阵 [acbd] 都需要满足 [a≤b]+[c>d]>0,即这两个条件至少满足一个;
那么由此可以得出一个性质:
并且也可以证明蒙日矩阵一定是完全单调矩阵,反证法:若 a>b 且 c≤d,则一定有 a+d>b+c。
-
根据蒙日矩阵的定义,check 一个矩阵 Mn×m 是否蒙日矩阵仅需 check 2×2 的连续子矩阵即可;
因为若 a+d≤b+c 则 a+d−b−c≤0,注意到这个是二维差分的形式,即 M 可以看作一个非正矩阵的二维前缀和,而 2×2 的子矩阵(不一定连续)的 a+d−b−c 相当于该非正矩阵一个矩形中数的和,显然其也非正;
故证明四边形不等式时仅需考虑 [l,r] 和 [l+1,r+1];
-
给蒙日矩阵中某一行整体加同一个数,矩阵仍是蒙日矩阵;
关于应用的定义
蒙日矩阵一般都是定义在区间上的,即 Mn×n,其中 Mi,j 是区间 [i,j] 的代价。
这样定义会带来一些问题,因为 i>j 的区间不存在,若将其简单定义为 ∞ 则会导致形如 [∞∞a∞] 的子矩阵会导出 ∞+∞≤∞+a 的错误式子,且形如 [∞∞ab] 的子矩阵会导出 b≤a 的不一定成立的式子(给某一行整体加同一个数不改变蒙日性,但此时可能有 b>a)。
一个聪慧的构造是考虑令 i<j 时 Mi,j=(j−i)2×∞,不难验证该构造满足蒙日性。
分治优化
本质其实是找到矩阵中第 mid 行的最小值的位置,并分治处理左和右下矩阵:
所以该方法仅要求矩阵是单调矩阵。
二分队列优化
本质上是从左往右扫每一列,对于每列维护出最小值在该列的行的区间,每次插入一列的时候干掉一个后缀的区间并插入一个新区间:
所以该方法仅要求矩阵是完全单调矩阵。
蒙日矩阵最短路——区间划分型 dp
不难发现,若将区间 (l,r] 的代价对应的蒙日矩阵看作 n 个点的图 G 的邻接矩阵,则序列的最小代价区间划分对应着由 0 到 n 的最短路。特别的,任意两点 l,r 间的最短路对应着区间 [l+1,r] 的最小代价区间划分。
一些性质
-
设 f(x,y,k) 为 x→y 的经过 k 条边的的蒙日矩阵最短路的长度,则 f(x,y,k) 关于 k 是凸的;
考虑证 f(x,y,k)−f(x,y,k−1)≤f(x,y,k+1)−f(x,y,k) 相当于证 2f(x,y,k)≤f(x,y,k−1)+f(x,y,k+1)。
将 f(x,y,k−1) 和 f(x,y,k+1) 对应的最短路径拿出来,考虑根据这两条路径构造两条长度为 k 的路径使得它们的和不变大。按照编号若某个点来自 k−1 则写下 a,否则写下 b,编号相同的顺序任意,得到序列 p[1,2k],那么 a 一定比 b 少两个。
考虑找到某个前缀 p[1,i] 满足 a 比 b 恰好少一个,且 pi=pi+1=b:
则此时 p[i+1,2k] 一定也满足 a 比 b 恰好少一个,那么可以这样构造两条长 k 的路径:
- p[1,i] 中的 a 接上 p[i+1,2k] 中的 b;
- p[1,i] 中的 b 接上 p[i+1,2k] 中的 a;
注意到由于 pi=pi+1=b,所以中间部分实际上是将一个包含变为了相交,故路径代价总和不增。
故证明一定能找到这样的 i 即可。
考虑折线图,将 a 看作 1,b 看作 −1,则该折线从 0 出发,在 −2 处终止。由于折线是连续的,故一定有某个时刻位于 −1,此时若下一个时刻位于 0,则后半部分递归了,否则就找到了连续的两个 b。