[dp 进阶]决策单调性
[dp 进阶] 决策单调性
四边形不等式
考虑这样一类 dp 转移问题:
其中 \(\min\) 和 \(\max\) 是对称等价的,为方便我们只讨论一种情况。
一种常见的对应模型是区间划分问题。假设 \(w(i, j)\) 可以 \(O(1)\) 计算,则直接转移是 \(O(n^2)\) 的,但我们可以根据 \(w(i, j)\) 的特殊性质来优化。
先明确一些定义:
- 此类 dp 转移可以称为一系列最优化问题。
- 每一个问题都是给定 \(i\),选择某个 \(j\),最优化函数关于 \(i\) 和 \(j\) 的函数值 \(g(j) + w(i, j)\)。简记参数为 \(i\) 的问题为问题 \(i\)。
- 从 \(j\) 转移的决策称为决策 \(j\),其中最优的决策记为 \(j = opt(i)\)。最优决策可能有多个。
我们声称:如果转移方程满足决策单调性,则转移的状态空间可以缩小,从而把时间复杂度优化到朴素的 \(O(n^2)\) 以下。
决策单调性:\(\forall i < j\),\(opt(i) \le opt(j)\)。即最优决策点非严格递增。
评注:如上文,最优决策可能有多个。此种情况下,我们认为决策单调性的定义为:最小的最优决策点非严格递增。
另外,(最小)最优决策点单增并不蕴含,对于问题 \(i\),\(f(i)\) 随着 \(j\) 的变大而变优。
最常见的判断决策单调性的方法是四边形不等式:
四边形不等式:如果二元函数 \(w(l, r)\) 满足 \(\forall a \le b \le c \le d\),
均成立,则此函数满足四边形不等式。这个条件可以简记为相交小于(等于)包含。
定理 如果 \(w\) 满足四边形不等式,则 dp 满足决策单调性。实际上,四边形不等式成立是决策单调性的充分非必要条件。
证明 使用反证法。若决策单调性不成立,则存在 \(a < b \le c < d\) 使得 \(opt(d) = a\),\(opt(c) = b\)。那么
移项得
与四边形不等式矛盾。
评注:有些人把转移方程的形式写为
\[f(i) = \min_{0 \le j < i} w(j, i) \]也就是把 \(g(j)\) 的贡献计算到 \(w(j, i)\) 中(例如 OI wiki),但这实际上是等价的。实际上可以证明:移除 \(w(j, i)\) 中只和 \(j\) 有关的项,不影响四边形不等式的成立。这是容易证明的,直接在不等式中移项,可以发现这些项都被消掉了。
二阶混合差分
四边形不等式的一个等价形式是:代价函数的二阶混合差分非正。
先来定义什么是二阶混合差分。对于一元函数 \(f(a)\),熟知其差分函数 \(\Delta f(a) = f(a) - f(a - 1)\)。对于二元函数 \(w(a, b)\)(\(a < b\)),由于它有两个自变量,我们先对其中一个自变量差分:记 \(w(a, b)\) 在 \(b\) 方向的差分为
在此基础上再对 \(a\) 方向差分:
定理 \(\Delta_{a}\Delta_{b} w(a, b) \le 0\),即
是 \(w\) 满足四边形不等式的充要条件。
证明
-
必要性:显然,此条件是“相交小于包含”的一个特例。
-
充分性:设 \(a < b \le c < d\),现在有 \(w(b, d) + w(b - 1, d - 1) \le w(b - 1, d) + w(b, d - 1)\)。记命题 \(P(k)\) 表示 \(w(b, d) + w(b - k, d - 1) \le w(b - k, d) + w(b, d - 1)\),我们考虑归纳证明 \(P(k) \Rightarrow P(k + 1)\)。
假设 \(P(k')\) 对 \(k' \le k\) 都成立,则
\[\begin{cases} w(b, d) + w(b - k + 1, d - 1) \le w(b - k + 1, d) + w(b, d - 1) \\ w(b - k + 1, d) + w(b - k, d - 1) \le w(b - k, d) + w(b - k + 1, d - 1) \end{cases} \]第一个不等式由 \(P(k - 1)\) 推出,第二个不等式是用 \(b - (k - 1)\) 代替 \(b\) 以后用 \(P(1)\) 推出。
两不等式相加得
\[\begin{aligned} w(b, d) + {\color{blue}w(b - k + 1, d - 1) + w(b - k + 1, d)} + w(b - k, d - 1) \\ \le {\color{blue}w(b - k + 1, d)} + w(b, d - 1) + w(b - k, d) + {\color{blue}w(b - k + 1, d - 1)} \end{aligned} \]消去蓝色的部分以后得
\[w(b, d) + w(b - k - 1, d - 1) \le w(b - k - 1, d) + w(b, d - 1) \]即 \(P(k + 1)\)。又由于 \(P(1)\) 成立,所以 \(P(k)\) 对任何 \(k \in \mathbb{N}^{+}\) 都成立。设 \(\Delta = b - a\),则从 \(P(\Delta)\) 可以推出
\[w(b, d) + w(a, d - 1) \le w(a, d) + w(b, d - 1) \]相当于用 \(a\) 代替了 \(b - 1\)。可以类似证明区间右端点也可以这样右移,从而四边形不等式成立。\(\Box\)
如果转移方程满足决策单调性,通常有两种方法来优化转移:
分治
设 \(mid = \lfloor n / 2 \rfloor\)。首先枚举 \([1, mid)\) 中所有决策点求解 \(k = opt(mid)\)。然后把未被求解决策点的区间分成两半:\([1, mid)\) 和 \((mid, n]\)。根据决策单调性,可知 \([1, mid)\) 中的决策点都不大于 \(k\),\((mid, n]\) 中的决策点都不小于 \(k\),可以递归下去求解。
在递归过程中,记录要求解决策点的区间 \([l, r]\) 和决策点可能在的区间 \([kl, kr]\)。那么,对于同一层中相邻的两个区间,两者可能的决策点区间的交集不超过 \(1\),所以每个决策点在每层最多求解 \(2\) 次。而层数为 \(O(\log n)\),因此总时间复杂度为 \(O(n \log n)\)。
这种方法是有局限性的,我们将会在下一节讲述。
例题
P3515 [POI 2011] Lightning Conductor
简单转化题意得:对每个 \(i\) 求解
首先把问题分成 \(j \le i\) 和 \(j > i\) 两部分。下面关注第一部分,另一部分是对称的。
设 \(g(j) = h_j\),\(w(j, i) = \sqrt{i - j}\)。我们要证明 \(w(j, i)\) 满足四边形不等式。注意:此处转移方程中含 \(\max\) 而非 \(\min\),四边形不等式中的不等号要取反,原因显然。
设 \(a \le b \le c \le d\),则
设 \(f(x) = \sqrt{x}\), \(x = d - b\),\(y = c - b\),\(\Delta = b - a \ge 0\),代入得
由于 \(\sqrt{x}\) 是上凸函数(\((\sqrt{x})' = \frac{1}{2\sqrt{x}}\) 单调减),所以上式非正,四边形不等式成立。我们会在下文详细讨论这点。
直接分治即可。代码
CF321E. Ciel and Gondolas
记文中的 \(k\) 为 \(m\)。
典型的划分区间问题。设 \(f_{k}(i)\) 表示前 \(i\) 人划分成 \(k\) 段的最小代价,\(w(l, r)\) 表示把 \((l, r]\) 中的人分到一段的代价,则有
考虑二维前缀和,则 \(w(j, i)\) 相当于一个子矩形的元素和的一半,那么四边形不等式显然成立(画个图就很明显)。枚举 \(k\),分治 \(m\) 次即可,时间复杂度 \(O(m n \log n)\)。好像有点卡常。代码
P4767 [IOI 2000] 邮局 加强版
分别记文中的 \(V, P\) 为 \(n, m\),第 \(i\) 个邮局的位置为 \(p_i\)。
首先转化一下题意。容易观察到,对于每个邮局,以这个邮局为最近邮局的村庄构成一段区间。于是可以想到划分区间 dp,每个区间有一个邮局。但问题在于,加入一个新区间时,没法保证这个区间内的村庄的最近邮局是我们加入的那个。但实际上无需考虑这种情况:我们要求的是最优值,如果某个村庄的贡献不是它到最近邮局的距离,那么一定不优,所以不影响答案。这种思想在最优化 dp 中很常见:对于某些转移中难以维护的限制,可以把这个限制放宽,然后证明放宽限制不影响答案,因为不满足限制的方案一定不优。
那么,设 \(f_k(i)\) 表示前 \(i\) 个村庄中有划分成 \(k\) 段的最小代价,则
其中 \(w(l, r)\) 表示把 \([l, r]\) 划分成一段的代价。现在要证明其满足四边形不等式。
评注:严谨地说,要证明的是 \(w'(j, i) = w(j + 1, i)\) 满足四边形不等式,但容易证明在保证 \(j < i\) 的情况下,两者是等价的。
根据经典结论,对于区间 \([l, r]\),邮局设在第 \(\left\lfloor \frac{l + r}{2} \right\rfloor\) 个村庄是最优的。容易列出 \(w(l, r)\) 用 \(p\) 的前缀和表示的式子,这样就可以 \(O(1)\) 计算,但从这个角度证明四边形不等式是困难的。换个思路,列出 \(w\) 的递推式,然后证明其二阶差分非正。记 \(s\) 表示 \(p\) 的前缀和,\(x = \left\lfloor \frac{l + r}{2} \right\rfloor\),那么有
当 \([l, r]\) 的长度是偶数时,\([l, r - 1]\) 和 \([l, r]\) 的中点相同,结论显然成立。否则,\([l, r - 1]\) 的长度为偶数,此时取 \(\left\lceil \frac{l + r - 1}{2} \right\rceil\) 作为它的中点同样是最优的,所以两个区间的中点仍然可以视为相同。因此上式确实成立。
现在证明四边形不等式就容易得多:
因此决策单调性成立。分治 \(m\) 次即可,时间复杂度 \(O(m n \log n)\)。
二分队列
分治的写法比较简洁,但它最大的缺点在于求解决策点的顺序是乱序的,而有时转移方程需要顺序求解。例如转移方程可能为
这种转移形式可以称为“自转移”。此时我们必须按 \(i\) 从小到大的顺序求解 \(f(i)\),因此分治法不再适用了。此时可以使用二分队列法。
由于决策单调性成立,对每个决策点 \(j\),以 \(j\) 作为最小最优决策点的问题构成一段区间。为了方便,如果问题区间 \([l, r]\) 以决策点 \(j\) 为最小最优决策点,则称 \(j\) “支配” \([l, r]\)。
具体地,维护一个双端队列,队列中的每个元素是一个三元组 \((j, l_j, r_j)\),表示决策 \(j\) 支配的区间为 \([l_j, r_j]\)。初始时队列为空,从小到大枚举 \(i\),求出在只考虑决策点 \([1, i]\) 的情况下,决策 \(i\) 在问题 \([i, n]\) 中支配的子区间。每个时刻,队列中的决策支配的区间构成 \([i, n]\) 的不交并,且区间的顺序有序。枚举到 \(i\) 时,要做两件事:
- 用决策 \(i\) 更新双端队列;
- 求出问题 \(i\) 的答案。
求出问题 \(i\) 的答案是有序的:更新完双端队列中的决策后,队首的决策支配的区间必定包含 \(i\),所以队首决策就是问题 \(i\) 的最优决策。关键是如何用决策 \(i\) 更新原先的决策。这个过程分为以下几个步骤:
- 删队首:如果队首决策 \(j\) 支配的区间右端点 \(r_j < i\),说明 \(j\) 不可能是 \(i\) 及以后的问题的最优决策,需要弹出。否则,把 \(l_j\) 设为 \(i\)。
- 删队尾:如果 \(i\) 支配的区间不为空,那么应该存在一个分界点 \(p\),使得 \([p, n]\) 中的问题的最优决策点不小于 \(i\),而 \([i, p)\) 中的问题的最优决策点小于 \(i\),我们需要求出这个 \(p\)。对于队尾决策 \(j\),如果 \(g(i) + w(i, l_j) < g(j) + w(j, l_j)\),也就是用 \(i\) 来转移 \(l_j\) 比用 \(j\) 来转移 \(l_j\) 更优,根据决策单调性,\([l_j, r_j]\) 整个区间用 \(i\) 转移都比用 \(j\) 转移更优,因此可以从队尾弹出 \(j\)。重复这个过程,直到队列为空或者此条件不成立。
- 加队尾:如果队列为空,则直接把 \((i, i, n)\) 加入队尾。否则设队尾决策为 \(j\),如果 \(g(i) + w(i, n) < g(j) + w(j, n)\),说明 \(i\) 支配的区间不为空,需要加队尾。此时可以确定 \(p\) 在 \((l_j, n]\) 中,于是就可以二分确定 \(p\)。然后把 \(r_j\) 修改为 \(p - 1\),并把 \((i, p, n)\) 加入队尾。
由于决策入队时可能需要二分,此算法的时间复杂度为 \(O(n \log n)\),和分治相同。
需要注意,二分队列法并不是对所有满足决策单调性的转移方程都适用。在加队尾操作中,我们可能需要二分确定位置 \(p\),使得对两个决策点 \(j < i\) 和区间 \([i, n]\),满足:\([j, p)\) 中的问题用 \(j\) 转移更优,\([p, n]\) 中的问题用 \(i\) 转移更优。这个性质和决策单调性并不等价。但可以证明:四边形不等式蕴含此性质。
定理 如果四边形不等式成立,则任取决策点 \(j < i\),存在分界点 \(p \ge i\),使得 \([j, p]\) 中的问题用 \(p\) 转移更优,\((p, n]\) 中的问题用 \(i\) 转移更优。(两个区间均可能为空。)
证明 我们将四边形不等式变为 \(w(b, c) - w(b, d) \le w(a, c) - w(a, d)\)。那么
可以看作对于两个决策点 \(a < b\),对于两个问题 \(c < d\),较大的决策点转移的增量更小,所以总是存在这样的分界点 \(p\)。\(\Box\)
综上所述,能使用二分队列的条件是:四边形不等式成立。
例题
P3515 [POI 2011] Lightning Conductor
推导同上。代码
P1912 [NOI2009] 诗人小G
设 \(a_i\) 表示第 \(i\) 个句子的长度, \(f(i)\) 表示排版前 \(i\) 个句子的最小代价,则
其中 \(w(j, i) = |s_{i} - s_{j} + i - j - 1 - L|^{P}\),\(s_{i} = \sum_{j = 1}^{i} a_{j}\)。可以证明 \(w(i, j)\) 满足四边形不等式(见下节)。
这是自转移的形式,只能二分队列。由于要输出方案,dp 时要记录转移点。另外这题中涉及的数比较大,需要使用 long double 在损失一定精度的情况下扩大值域,这在答案不超过 \(10^{18}\) 时精度是足够的。(更严谨的方法或许是使用高精度,但我不知道会不会 TLE。)
Code
#include<bits/stdc++.h>
#define all \
for(auto dq: {&que, &l, &r}) (*dq)
typedef long long i64;
typedef long double Z;
constexpr Z INF = 1E18;
constexpr int ml = 30;
void solve() {
int n, L, P;
std::cin >> n >> L >> P;
std::vector<std::string> s(n + 1);
std::vector<int> a(n + 1);
for(int i = 1; i <= n; i++) {
std::cin >> s[i];
a[i] = (int)s[i].size();
}
std::vector<int> sum(n + 1);
partial_sum(a.begin() + 1, a.end(), sum.begin() + 1);
std::vector<Z> pw(std::max(L, ml * n) + 1, INF + 1);
pw[0] = 0;
for(int i = 1; i <= std::max(L, ml * n); i++) {
pw[i] = 1;
for(int j = 1; j <= P; j++) {
pw[i] *= i;
}
}
auto w = [&](int l, int r) {
return pw[abs(sum[r] - sum[l] + r - l - 1 - L)];
};
std::vector<Z> f(n + 1, INF + 1);
f[0] = 0;
std::vector<int> g(n + 1);
std::deque<int> que, l, r;
que.push_back(0), l.push_back(1), r.push_back(n);
for(int i = 1; i <= n; i++) {
if(!que.empty() && r.front() == i - 1) all.pop_front();
if(!que.empty()) l.front() = i;
f[i] = w(que.front(), i) + f[que.front()];
g[i] = que.front();
if(f[i] > INF) {
continue;
}
while(!que.empty() && f[i] + w(i, l.back()) < f[que.back()] + w(que.back(), l.back())) {
all.pop_back();
}
if(que.empty()) {
que.push_back(i), l.push_back(i), r.push_back(n);
} else if(f[i] + w(i, n) < f[que.back()] + w(que.back(), n)) {
int lo = l.back(), hi = n, p = -1;
while(lo <= hi) {
int mid = (lo + hi) >> 1;
if(f[i] + w(i, mid) < f[que.back()] + w(que.back(), mid)) {
p = mid, hi = mid - 1;
} else {
lo = mid + 1;
}
}
assert(p != -1);
r.back() = p - 1;
que.push_back(i), l.push_back(p), r.push_back(n);
}
}
auto print = [&](auto &&self, int p) -> void {
if(p > 0) {
self(self, g[p]);
}
for(int i = g[p] + 1; i <= p; i++) {
std::cout << s[i] << " \n"[i == p];
}
};
if(f[n] > INF) {
std::cout << "Too hard to arrange\n";
} else {
std::cout << (i64)f[n] << '\n';
print(print, n);
}
std::cout << "--------------------\n";
}
int main() {
std::cin.tie(nullptr) -> sync_with_stdio(false);
int t;
std::cin >> t;
while(t--) {
solve();
}
return 0;
}
一类区间分拆问题
区间分拆问题是决策单调性的经典模型,上文一些例题就属于此模型:给定区间 \([1, n]\),需要把它划分成若干子区间,最小化每个子区间的代价之和。记 \(w(l, r)\) 表示区间 \([l, r]\) 的代价,可以列出 1D1D 转移方程:
如果 \(w(l, r)\)。满足四边形不等式,则可以用决策单调性优化。由于方程为自转移,通常只能使用二分队列算法。
有时问题要求划分的区间数为一给定值 \(m\),此时有 2D1D 转移方程:
使用 \(m\) 次二分队列可以做到 \(O(m n \log n)\)。但根据四边形不等式的性质,还有两种优化方式。
层间决策单调性
定理 记 \(opt(k, i)\) 表示 \(f_k(i)\) 的最小最优决策点,则 \(opt(k - 1, i) \le opt(k, i) \le opt(k, i + 1)\)。
证明 第二个不等号即为层内的决策单调性,关键在于第一个不等号:这意味着层间的同一位置也有决策单调性。
利用这一结论,我们可以在转移时缩小决策点的范围。dp 时,正向枚举 \(k\),逆向枚举 \(i\),则计算 \(f_k(i)\) 时只需枚举 \([opt(k - 1, i), opt(k, i + 1)]\) 中的决策点。这样做看上去很暴力,但它的时间复杂度为 \(O(n(n + m))\) 而非朴素的 \(O(mn^2)\):考虑所有问题构成的 \(m \times n\) 的表格,则一条次对角线上的每个问题的决策点范围,都被上面一条次对角线中的两个问题限定。那么暴力查找一条次对角线上所有问题的决策点的时间复杂度为 \(O(n)\),而次对角线的数量为 \(O(n + m)\),因此总时间复杂度为 \(O(n(n + m))\)。
例题
P4767 [IOI 2000] 邮局 加强版
Code
#include<bits/stdc++.h>
using namespace std;
typedef long long i64;
constexpr i64 INF = 0x3f3f3f3f'3f3f3f3f;
int main() {
cin.tie(nullptr) -> sync_with_stdio(false);
int n, m;
cin >> n >> m;
vector<i64> a(n + 1);
for(int i = 1; i <= n; i++) {
cin >> a[i];
}
vector<i64> sum(n + 1);
partial_sum(a.begin() + 1, a.end(), sum.begin() + 1);
auto w = [&](int l, int r) {
int x = (l + r) >> 1;
return ((sum[r] - sum[x]) - (r - x) * a[x]) + ((x - l + 1) * a[x] - (sum[x] - sum[l - 1]));
};
array<vector<i64>, 2> f;
array<vector<int>, 2> opt;
f.fill(vector<i64>(n + 1, INF)), opt.fill(vector<int>(n + 2));
f[0][0] = 0;
for(int k = 1; k <= m; k++) {
fill(f[1].begin() + 1, f[1].end(), INF), opt[1][n + 1] = n;
for(int i = n; i >= 1; i--) {
for(int j = opt[0][i]; j <= opt[1][i + 1]; j++) {
i64 tmp = f[0][j] + w(j + 1, i);
if(tmp < f[1][i]) {
f[1][i] = tmp, opt[1][i] = j;
}
}
}
f[0].swap(f[1]), opt[0].swap(opt[1]);
}
cout << f[0][n] << '\n';
return 0;
}
凸优化(WQS 二分)
定理 设 \(g(k) = f_k(n)\),则 \(g(k)\) 下凸。
也就是说,在限定区间个数的区间划分问题中,如果区间代价函数 \(w\) 满足四边形不等式,则全局最小代价关于区间数量下凸。
证明 根据琴生不等式,只需证明 \(g(k + 1) + g(k - 1) \ge 2g(k)\)。
根据此结论,可以在状态中去掉划分段数的维度,套上 WQS 二分,从而把时间复杂度优化到 \(O(n \log n \log w)\),其中 \(w\) 为某一与值域有关的值。
例题
[IOI 2000] 邮局 加强版 加强版
WQS 二分套二分队列板子题。
满足四边形不等式的函数类
定理 设 \(h(x)\) 是凸函数,若 \(w(l, r)\) 满足四边形恒等式且对区间包含关系满足单调性,则二元复合函数 \(h(w(i, j))\) 也满足四边形不等式。
证明
举例:上文提到,在 P1912 [NOI2009] 诗人小G 一题中,代价函数为 \(w(l, r) = |s_r - s_l + r - l - 1 - L|^P\),其中 \(s\) 是正数序列 \(a\) 的前缀和数组。为了方便,令 \(a_i \gets a_i + 1\),\(L \gets L + 1\),则
记 \(w'(l, r) = s_r - s_l - L\),\(h(x) = |x|^P\)。容易证明 \(w'(l, r)\) 满足四边形恒等式和区间包含单调性,又 \(|x|^P\) 显然是凸函数,所以 \(w(l, r) = h(w'(l, r))\) 满足四边形不等式。

浙公网安备 33010602011771号