从决策单调性到四边形不等式
从决策单调性到四边形不等式
今天上课浅学了一下,还是有点懵,于是就准备用这篇博文整理一下。
本篇文章主要讨论四边形不等式在有关 1D/1D 类问题中的应用,区间类暂不涉及。
参考:OI-Wiki
引入
我们为什么需要决策单调性?
我们之前常见的 dp 优化有很多,如单调队列,如斜率优化,如矩阵优化,等等。但是,这些优化都无法解决一些更普遍的方程,这类方程形如(这里以最小值为例):
或者,我们改写为区间的形式,那么就是:
这里的
四边形不等式
定义
若
性质(这里只列出两个我认为会用到的)
- 若函数
均满足四边形不等式,则对于 ,函数 也满足四边形不等式。 - 若存在函数
,使得 ,则函数 满足四边形恒等式。
可以通过定义证明。
决策单调性
判定
那么,四边形不等式是如何应用到决策单调性上的呢?
结论:如果函数
简要证明:
我们不妨设
我们令不等式上下相加、消元,就得到
有了这个性质,我们就可以搞出来一个题是否具有决策单调性了。
求解
光能推出来决策单调性还不够,我们要去用这个性质。
这里给出递归求解的过程。
我们考虑分治,令
代码:
void solve1(int ql, int qr, int l, int r){//处理的dp区间与最优决策点所在区间 if(ql>qr) return; int mid = (ql+qr)>>1; int pos = 0; int limi = min(mid-1, r); for(int i = l; i<=limi; ++i){ double tmp = W1(i, mid); if(tmp>f[mid]) f[mid] = tmp, pos = i; } solve1(ql, mid-1, l, pos); solve1(mid+1, qr, pos, r); }
例题
Lightning Conductor
首先这和高中一类数学题很像:恒成立问题。于是我们自然而然想到要分离变量,于是有
由四边形不等式的性质,我们发现
代码:
#include<bits/stdc++.h> using namespace std; const int N = 5e5+10; inline int read(){ int x = 0; char ch = getchar(); while(ch<'0' || ch>'9') ch = getchar(); while(ch>='0'&&ch<='9') x = x*10+ch-48, ch = getchar(); return x; } int a[N], n; double W1(int l, int r){ return a[l]-a[r]+1.0*sqrt(r-l); } double W2(int r, int l){ return a[r]-a[l]+1.0*sqrt(r-l); } double f[N], g[N]; void solve1(int ql, int qr, int l, int r){//处理的dp区间与最优决策点所在区间 if(ql>qr) return; int mid = (ql+qr)>>1; int pos = 0; int limi = min(mid-1, r); for(int i = l; i<=limi; ++i){ double tmp = W1(i, mid); if(tmp>f[mid]) f[mid] = tmp, pos = i; } solve1(ql, mid-1, l, pos); solve1(mid+1, qr, pos, r); } void solve2(int ql, int qr, int l, int r){ if(ql>qr) return; int mid = (ql+qr)>>1; int pos = 0; int limi = max(mid+1, l); for(int i = r; i>=limi; --i){ double tmp = W2(i, mid); if(tmp>g[mid]) g[mid] = tmp, pos = i; } solve2(mid+1, qr, pos, r); solve2(ql, mid-1, l, pos); } int main(){ n = read(); for(int i = 1; i<=n; ++i){ a[i] = read(); } solve1(1, n, 1, n); solve2(1, n, 1, n); for(int i = 1; i<=n; ++i){ printf("%d\n", (int)ceil(max(f[i], g[i]))); } return 0; }