学习笔记:决策单调性优化DP
决策单调性优化是对求最优化DP问题加速转移的一种方法。
前缀转移
形如 \(f(i) = \min\limits_{j<i} g(j)+w(j,i)\) 的转移方程被称为前缀转移方程,本质上就是划分区间。
若 \(f=g\),称它为自转移;否则称为他转移。
我们称转移到 \(i\) 的 \(j\) 为决策点,记为 \(opt(i)\),\(i\) 为被决策点。对于同一个 \(i\) 可能存在多个决策点。
对于前缀转移,决策单调性的定义如下:
-
若 \(i_1\le i_2\),
-
对于任意 \(opt(i_1)\),存在 \(opt(i_2)\ge opt(i_1)\),
-
对于任意 \(opt(i_2)\),存在 \(opt(i_1)\le opt(i_2)\)。
显然所有 \(i\) 的最左侧的 \(opt(i)\) 是单调的。
分治
若 \(f\) 是前缀转移,且是他转移,则可以用分治求解。
-
初始 \([l,r]=[1,n]\),
-
记 \(mid = \frac{l+r}{2}\),求解 \(opt(mid)\),
-
递归到 \([l, mid - 1]\),并只用在 \([l,opt(mid)]\) 中找决策点,
-
递归到 \([mid + 1, r]\),并只用在 \([opt(mid),r]\) 中找决策点,
-
复杂度 \(O(n\log n)\)。
若 \(f\) 为自转移,需要进行更多讨论。
四边形不等式
若对于任意 \(a\le b\le c\le d\),有 \(w(a,c) + w(b,d)\le w(b,c) + w(a,d)\),则 \(w\) 满足四边形不等式。可简记为 "相交小于包含"。
定理 \(1\)
若 \(w\) 满足四边形不等式,则 \(f\) 具有决策单调性。
证明 \(1\)
考虑反证,假设 \(f\) 不满足决策调性,但满足四边形不等式。设 \(opt(c) = b\),\(opt(d) = a\),\(a< b\le c< d\),这里都取最左侧决策点,
则有 \(g(a)+w(a,d)\le g(b)+w(b,d)\),\(g(b)+w(b,c)< g(a)+w(a,c)\),
因此 \(g(a)-g(b)+w(a,d)-w(b,d)\le 0<g(a)-g(b)+w(a,c)-w(b,c)\),两边同时消去 \(g(a)-g(b)\),则 \(w\) 不满足四边形不等式,与假设矛盾。
定理 \(2\)
我们将四边形不等式变形为 \(w(a,d)-w(a,c)\ge w(b,d)-w(b,c)\),则 \((g(a)+w(a,d))-(g(a)+w(a,c)) \ge (g(b)+w(b,d))-(g(b)+w(b,c))\),
形象地说,被决策点增大时,越靠后的决策点,转移的代价的增量越小,
那么对于决策点 \(j_1<j_2\),存在一个分界点 \(x>j_2\),使得 \(j_2<i<x\) 的决策点由 \(j_1\) 转移,\(i\ge x\) 的决策点由 \(j_2\) 转移。
我们不妨把这个性质称为,"逐渐变劣"性质。
LGP3515 [POI 2011] Lightning Conductor
Solution
\(a_j\le a_i+p_i-\sqrt{|i-j|}\),
\(p_i = \max\limits_{j} a_j-a_i+\sqrt{|i-j|} = \max\{\max\limits_{j<i}a_j-a_i+\sqrt{i-j}, \max\limits_{j>i}a_j-a_i+\sqrt{j-i}, 0\}\),
分两遍求,接下来证明左边满足决策单调性,右边同理。
设 \(w(i,j) = a_j - a_i + \sqrt{i-j}\),设 \(i<j<k<t\),
\(w(i,k)+w(j,t) - w(i,t)-w(j,k) = \sqrt{k-i}-\sqrt{k-j}-(\sqrt{t-i}-\sqrt{t-j})\),
由于 \(y=\sqrt x\) 这个函数随着 \(x\) 增大,每次变化量越来越小,因此上面的式子 \(>0\),由于是 \(\max\),因此四边形不等式要变成 \(\ge\),因此 \(w\) 满足四边形不等式,也就满足决策单调性。
Code
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
using ULL = unsigned long long;
using LD = long double;
using PII = pair<int, int>;
const int N = 5e5 + 5;
double INF = 2e9 + 5;
int n;
double a[N], f0[N], f1[N];
void work0(int l, int r, int L, int R) {
if (l > r) return;
int mid = l + r >> 1, cur = 0;
for (int i = L; i <= min(R, mid - 1); i++) {
double val = a[i] - a[mid] + sqrt(mid - i);
if (val > f0[mid]) {
cur = i;
f0[mid] = val;
}
}
work0(l, mid - 1, L, cur);
work0(mid + 1, r, cur, R);
}
void work1(int l, int r, int L, int R) {
if (l > r) return;
int mid = l + r >> 1, cur = 0;
for (int i = R; i >= max(L, mid + 1); i--) {
double val = a[i] - a[mid] + sqrt(i - mid);
if (val > f1[mid]) {
cur = i;
f1[mid] = val;
}
}
work1(l, mid - 1, L, cur);
work1(mid + 1, r, cur, R);
}
int main() {
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = 1; i <= n; i++) f0[i] = f1[i] = -INF;
work0(1, n, 1, n);
work1(1, n, 1, n);
for (int i = 1; i <= n; i++) cout << (int)ceil(max({f0[i], f1[i], 0.0})) << '\n';
return 0;
}
CF321E Ciel and Gondolas
Solution
设 \(f(i,j)\) 表示前 \(i\) 个人划分成 \(k\) 段的最小价值,
\(f(i,j) = \min\limits_{k<i} f(k,j-1)+w(k+1,j)\),\(w(i,j)=\sum\limits_{k=i}^{j} \sum\limits_{t=k}^{j} u(k,t)\),
显然 \(w\) 满足四边形不等式,所以做 \(k\) 次分治即可,复杂度 \(O(kn\log n)\)。
Code
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
using ULL = unsigned long long;
using LD = long double;
using PII = pair<int, int>;
namespace FastIO {
template <typename T>
inline T read() {
T x = 0, w = 1;
char ch = 0;
while (ch < '0' || ch > '9') { if (ch == '-') w = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar(); }
return x * w;
}
template <typename T>
inline void write(T x, char c) {
static T sta[35];
T top{};
do { sta[top++] = x % 10, x /= 10; } while(x);
while (top) putchar(sta[--top] + 48);
putchar(c);
}
} using FastIO::read, FastIO::write;
const int N = 4005, INF = 1e9;
int n, k, a[N][N], dp[2][N];
inline int get_sum(int x1, int y1, int x2, int y2) {
return a[x2][y2] - a[x2][y1 - 1] - a[x1 - 1][y2] + a[x1 - 1][y1 - 1];
}
void work(int l, int r, int L, int R, int now) {
if (l > r) return;
int mid = l + r >> 1, val = 0, cur = 0;
dp[now][mid] = INF;
for (int i = min(R, mid); i >= L; i--) {
val = get_sum(i, i, mid, mid) / 2 + dp[now ^ 1][i - 1];
if (val < dp[now][mid]) {
dp[now][mid] = val;
cur = i;
}
}
work(l, mid - 1, L, cur, now);
work(mid + 1, r, cur, R, now);
}
int main() {
cin >> n >> k;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
a[i][j] = read<int>();
a[i][j] += a[i][j - 1] + a[i - 1][j] - a[i - 1][j - 1];
}
dp[0][i] = INF;
}
// for (int i = 1; i <= n; i++) {
// for (int j = 1; j <= n; j++) {
// cout << a[i][j] << ' ';
// }
// cout << '\n';
// }
for (int i = 1; i <= k; i++) work(1, n, 1, n, i & 1);
write<int>(dp[k & 1][n], '\n');
return 0;
}
定理 \(3\)
若对于任意 \(a< b\),有 \(w(a,b)+w(a-1,b-1)\le w(a-1,b)+w(a,b-1)\),
那么 \(w\) 满足四边形不等式。
证明 \(3\)
必要性显然满足,下证充分性。
对于 \(b\le d\),有
\(w(b,d)+w(b-1,d-1)\le w(b-1,d)+w(b,d-1)\),\((1)\)
\(w(b-1,d)+w(b-2,d-1)\le w(b-2,d)+w(b-1,d-1)\),\((2)\)\((1)+(2)\) 得,\(w(b,d)+w(b-2,d-1)\le w(b-2,d)+w(b,d-1)\),
不妨设 \(a=b-k\),\(a\le b\),那么通过这样不断减一,可以得到,
\(w(b,d)+w(a,d-1)\le w(a,d)+w(b,d-1)\),\((3)\)假设 \(d-1\ge b\),那么有,
\(w(b,d-1)+w(a,d-2)\le w(a,d-1)+w(b,d-2)\),\((4)\)\((3)+(4)\) 得,\(w(b,d)+w(a,d-2)\le w(a,d)+w(b,d-2)\),
不妨设 \(c=d-k\),\(b\le c\le d\),那么通过不断减一,可以得到,
\(w(b,d)+w(a,c)\le w(a,d)+w(b,c)\),证毕。
LGP4767 [IOI 2000] 邮局 加强版
Solution
首先可以发现,每个邮局控制的村庄一定是一段区间,那么原问题等价于把 \(n\) 个村庄划分成 \(m\) 个区间的最小代价。
设 \(dp(i,j)\) 表示将前 \(i\) 个村庄划分为 \(j\) 个区间的最小代价。\(dp(i,j)=\min\limits_{1\le k\le i} dp(k-1,j-1)+w(k,i)\)。
设 \(w(l,r)\) 表示区间 \([l,r]\) 的代价,容易发现把邮局放在 \(\lfloor \frac{l+r}{2}\rfloor\) 的位置是最优的,于是可以写出递推式 \(w(l,r)=w(l,r-1)+X(r)-X(\lfloor \frac{l+r}{2}\rfloor)\)。
这个式子为什么是对的?若 \([l,r-1]\) 长度为奇数,\(\lfloor \frac{l+r-1}{2}\rfloor = \lfloor \frac{l+r}{2}\rfloor\);若为偶数,\(\lfloor \frac{l+r-1}{2}\rfloor+1=\lfloor \frac{l+r}{2}\rfloor\),中点会移动一格,但是左边增加的距离和右边减少的距离抵消了,因此也是对的。
移项得到 \(w(l,r)-w(l,r-1)=X(r)-X(\lfloor \frac{l+r}{2}\rfloor)\),\((1)\)
\(w(l-1,r)-w(l-1,r-1)=X(r)-X(\lfloor \frac{l+r-1}{2}\rfloor)\),\((2)\)
由 \((1) - (2)\) 得,原式 \(= X(\lfloor \frac{l+r-1}{2}\rfloor)-X(\lfloor \frac{l+r}{2}\rfloor)\le 0\),
于是 \(w(l,r)-w(l,r-1)-w(l-1,r)+w(l-1,r-1)\le 0\),
\(w(l,r)+w(l-1,r-1)\le w(l,r-1)+w(l-1,r)\),
因此 \(w\) 是满足四边形不等式的。
于是分治 \(O(mn\log n)\) 求解即可。
Code
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
using ULL = unsigned long long;
using LD = long double;
using PII = pair<int, int>;
const int N = 3005, INF = 2e9;
int n, m, a[N], w[N][N], dp[2][N];
void work(int l, int r, int L, int R, int now) {
if (l > r) return;
int mid = l + r >> 1, cur = 0;
dp[now][mid] = INF;
for (int i = L; i <= min(R, mid); i++) {
int val = dp[now ^ 1][i - 1] + w[i][mid];
if (val < dp[now][mid]) {
dp[now][mid] = val;
cur = i;
}
}
work(l, mid - 1, L, cur, now);
work(mid + 1, r, cur, R, now);
}
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> a[i];
dp[0][i] = INF;
}
sort(a + 1, a + 1 + n);
for (int len = 2; len <= n; len++) {
for (int l = 1; l + len - 1 <= n; l++) {
int r = l + len - 1;
w[l][r] = w[l][r - 1] + a[r] - a[l + r >> 1];
}
}
for (int i = 1; i <= m; i++) work(1, n, 1, n, i & 1);
cout << dp[m & 1][n] << '\n';
return 0;
}
定理 \(4\)
对于限制区间个数的问题,设 \(f(i,j)\) 表示将 \([1,i]\) 划分为 \(j\) 个区间的最小代价,\(f(i,j)=\min\limits_{1\le k\le i} f(k-1,j-1)+w(k,i)\)。
若 \(w\) 满足决策单调性,则 \(opt(i,j-1)\le opt(i,j)\le opt(i+1,j)\)。
根据这个定理,我们倒序枚举第一维,正序枚举第二维,即可保证 \(f(i,j-1)\) 和 \(f(i+1,j)\) 在 \(f(i,j)\) 前被求解,它们的 \(opt\) 就可以记录下来,于是可以在 \([opt(i,j-1),opt(i+1,j)]\) 这个区间内查找 \(opt(i,j)\),
但是要注意这里的复杂度并不是 \(O(nm)\)。考虑我们要求解一个 \(n\times m\) 的状态矩阵,那么对于 \(i-j\) 为定值的 \(f(i,j)\),在矩阵中为一条对角线,总共的枚举次数为 \(O(n)\),但是这样的对角线有 \(O(n+m)\) 条,所以复杂度为 \(O(n(n+m))\)。
证明 \(4\)
\(opt(i,j)\le opt(i+1,j)\) 就是第一维的决策单调性,前面已经证过了。
考虑反证,设 \(opt(i,j-1) > opt(i,j)\),
对于问题 \(f(i,j)\),假设其在 \([1,i]\) 的最优划分为,\([a_j,b_j]\dots [a_1,b_1]\),
对于问题 \(f(i,j-1)\),假设其在 \([1,i]\) 最优划分为,\([c_{j-1},d_{j-1}]\dots [c_1,d_1]\),注意这里标号是倒序的。若 \(opt(i,j-1) > opt(i,j)\),则有 \(a_1 < c_1\)。
若 \(a_k<c_k\),显然 \(b_{k-1}<d_{k-1}\)。
因为我们一直是从左往右考虑,\(opt(b_j)=a_j\),\(opt(d_j)=c_j\);假若我们以 \(i\) 为起点,从右往左考虑,那么有 \(opt'(a_j)=b_j\),\(opt'(c_j)=d_j\),这时候,\(f'(x,y)\) 就表示把 \([x,i]\) 划分为 \(y\) 个区间的最小代价,那么对于 \(opt(a_{k-1})=b_{k-1}\) 和 \(opt(c_{k-1})=d_{k-1}\),可以看成是同一个维度的问题 \(f'(*,k-1)\) 的决策点,由于同一维度的决策单调性我们已经证过了,所以 \(a_{k-1}<c_{k-1}\),
那这样不断迭代下去,得到 \(a_{j-1} < c_{j-1}\),这显然不能成立,于是 \(opt(i,j)\le opt(i+1,j)\) 得证。
LGP4767 [IOI 2000] 邮局 决策单调性二次优化
Code
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
using ULL = unsigned long long;
using LD = long double;
using PII = pair<int, int>;
const int N = 3005, INF = 2e9;
int n, m, a[N], w[N][N], dp[N][305], opt[N][305];
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> a[i];
opt[i][0] = 1; // 处理边界
dp[i][0] = INF;
}
sort(a + 1, a + 1 + n);
for (int len = 2; len <= n; len++) {
for (int l = 1; l + len - 1 <= n; l++) {
int r = l + len - 1;
w[l][r] = w[l][r - 1] + a[r] - a[l + r >> 1];
}
}
for (int j = 1; j <= m; j++) {
opt[n + 1][j] = n; // 处理边界
for (int i = n; i >= 1; i--) {
dp[i][j] = INF;
for (int k = opt[i][j - 1]; k <= min(i, opt[i + 1][j]); k++) {
if (dp[k - 1][j - 1] + w[k][i] < dp[i][j]) {
dp[i][j] = dp[k - 1][j - 1] + w[k][i];
opt[i][j] = k;
}
}
}
}
cout << dp[n][m] << '\n';
return 0;
}
二分队列
能用二分队列的前提是满足 "逐渐变劣"性质,也就是四边形不等式,而不仅仅是普通决策单调性的定义。
设 \(x_j\) 表示决策点 \(j\) 在分界点 \(x_j\) 之后劣于决策点 \(j+1\),
因此,若 \(x_{j-1}\ge x_j\),那么在 \(j\) 变得比 \(j-1\) 更优之前,\(j+1\) 会先比 \(j\) 更优,所以 \(j\) 不可能被选择,可以不用考虑。
若重复上述删除过程,我们可以得到一系列 \(x\) 单调递增的决策点 \(j_1,j_2,\dots,j_k\),
那么若当前被决策的是 \(i\),然后某个 \(j\) 的 \(x_j < i\),那么这个 \(j\) 也可以删去。
那么根据这个,我们可以考虑维护 \(x\) 递增且首项最优的决策点序列,来进行加速转移,
-
假设已经决策完 \(i-1\),并维护了对于 \(i-1\) 的决策点序列 \(j_1,j_2,\dots,j_k\),现在要决策 \(i\),
-
先计算 \(i-1\) 与 \(j_k\) 的分界点 \(x_k\),若 \(x_k \le x_{k-1}\),则删去 \(j_k\),不断重复,最后加入 \(i-1\),
-
若对于 \(i\),\(x_{j_1}<i\),则删去 \(j_1\),不断重复,最后的 \(j_1\) 即为 \(i\) 的决策点。
-
可以用双端队列维护决策点,并用二分求解 \(x\)。于是这种方法可以将 自转移或他转移 优化到 \(O(n\log n)\),被称作 二分队列。
LGP1912 [NOI2009] 诗人小G
转换一下题意,给定长度为 \(n\) 的序列 \(a\),将 \(a\) 划分成任意段,每段的代价为 \(|\sum\limits_{i=l}^{r} a_i - L|^P\),求一种划分方案使得代价和最小。
Solution
设 \(f(i)\) 表示前 \(i\) 个划分的最小代价,有转移 \(f(i) = \min\limits_{j<i} f(j)+|S_i-S_j-L|^P\)。其中 \(S\) 为 \(a\) 的前缀和。
关于这题的决策单调性证明,我觉得用图像分析来理解的话,特别方便。
那么要证决策单调性,我们考虑能不能从 四边形不等式 或者 "逐渐变劣"性质 来证明。
设 \(w_i(j) = |S_j-S_{i}-L|^P\),是一个关于 \(j\) 的函数,
那么我们可以把 \(f\) 的转移方程改写为,\(f(i) = \min\limits_{j<i} f(j)+w_j(i)\),
接下来要证明 \(w_a(d)-w_a(c)\ge w_b(d)-w_b(c)\),\(a<b<c<d\),也就是 "逐渐变劣"性质。
由于 \(w_b(x) = w_a(x+C)\),其中 \(C=S_a-S_b\),我们都知道,函数自变量加上一个常数,就相当于左右平移。
可以先画出 \(w_a\) 和 \(w_b\) 的图像,大概是这样的,

于是就证明了决策单调性,由于是自转移,用二分队列即可。
注意题目中的 \(a_i\) 还要算上空格,因此初始让 \(a_i=len(string)+1\),然后 \(L+1\) 即可,因为末尾没有空格,要减 \(1\)。
Code
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
using ULL = unsigned long long;
using LD = long double;
using PII = pair<int, int>;
const int N = 1e5 + 5;
int n;
string s[N];
int pre[N], x[N];
LD f[N], a[N], L, P;
LD fpow(LD a, int b) {
LD ans = 1;
for (; b; b >>= 1) {
if (b & 1) ans = ans * a;
a = a * a;
}
return ans;
}
inline LD val(int j, int i) {
if (j == i) return 0;
return f[j] + fpow(abs(a[i] - a[j] - L), P);
}
int calc(int j, int i) {
int l = i, r = n, mid;
while (l < r) {
mid = l + r + 1 >> 1;
if (val(j, mid) <= val(i, mid)) l = mid;
else r = mid - 1;
}
return r;
}
void write(int x) {
if (!x) return;
write(pre[x]);
for (int i = pre[x] + 1; i <= x; i++) cout << s[i] << (i == x ? '\n' : ' ');
}
struct Deque {
int a[N], tl, hd;
inline void clear() { hd = 1, tl = 0; }
inline bool empty() { return tl < hd; }
inline void push_back(int x) { a[++tl] = x; }
inline void pop_back() { tl--; }
inline void pop_front() { hd++; }
inline int front() { return a[hd]; }
inline int back() { return a[tl]; }
inline int size() { return tl - hd + 1; }
inline int begin() { return hd; }
inline int end() { return tl; }
} dq;
void Solve() {
cin >> n >> L >> P;
L++;
for (int i = 1; i <= n; i++) {
cin >> s[i];
a[i] = s[i].size() + 1;
a[i] += a[i - 1];
}
f[0] = 0;
dq.clear();
dq.push_back(0);
for (int i = 1; i <= n; i++) {
while (dq.size() > 1 && x[dq.front()] < i) dq.pop_front();
int j = dq.front();
f[i] = val(j, i);
pre[i] = j;
while (dq.size() > 1 && x[dq.a[dq.end() - 1]] >= calc(dq.back(), i)) dq.pop_back();
x[dq.back()] = calc(dq.back(), i);
dq.push_back(i);
}
if (f[n] > 1e18) {
cout << "Too hard to arrange\n";
cout << "--------------------\n";
return;
}
cout << (LL)f[n] << '\n';
write(n);
cout << "--------------------\n";
}
int main() {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int T;
cin >> T;
for (int i = 1; i <= T; i++) Solve();
return 0;
}
区间转移
形如 \(f(i,j)=\min\limits_{i\le k<j} f(i,k)+f(k+1,j)+w(i,j)\) 的方程被称为区间转移方程。
一般只考虑自转移的情况,否则归纳为前缀转移方程。
同样的,我们设 \(opt(i,j)\) 表示 \(f(i,j)\) 的最佳且是最左端的决策点 \(k\),\((i,j)\) 为被决策点。
对于区间转移,决策单调性定义如下:
- 对于 \(i_1\le i_2\),\(j_1\le j_2\),有 \(opt(i_1,j_1)\le opt(i_2,j_2)\)。
根据决策单调性,对于 \(i<j\),有 \(opt(i,j-1)\le opt(i,j)\le opt(i+1,j)\),由于 \(f(i,j-1)\) 和 \(f(i+1,j)\) 比 \(f(i,j)\) 先被求解,那么可以直接在这个范围内枚举计算 \(opt(i,j)\)。于是对于同样长度的区间,枚举次数和为 \(O(n)\),一共有 \(O(n)\) 种长度,所以复杂度从朴素的 \(O(n^3)\) 优化到了 \(O(n^2)\)。
区间包含单调性
若对于 \(a\le b\le c\le d\),有 \(w(b,c)\le w(a,d)\),则称 \(w\) 满足区间包含单调性。
本质上是要求 \(w(i,j)\) 关于 \(i\) 递减,关于 \(j\) 递增。
定理 \(5\)
若 \(w\) 同时满足四边形不等式和区间包含单调性,则 \(f\) 满足决策单调性。
证明 \(5\)
先证明若 \(w\) 同时满足四边形不等式和区间包含单调性,则 \(f\) 也满足四边形不等式。
设 \(a\le b\le c\le d\),
考虑数学归纳法,按照 \(d-a\) 从小到大的顺序归纳。
首先对于 \(d-a=0\) 的情况,显然是成立的。
设 \(e = opt(a,d)\),
若 \(c\le e\) 或 \(e < d\),不妨设 \(c\le e\),第二种情况同理。
\(f(a,d)+f(b,c) = f(a,e)+f(e+1,d)+w(a,d)+f(b,c)\),
因为 \(e-a<d-a\),根据归纳假设,有 \(f(a,d)+f(b,c)\ge f(a,c)+f(b,e)+f(e+1,d)+w(a,d)\),
根据 \(w\) 的区间包含单调性,有 \(f(a,d)+f(b,c)\ge f(a,c)+f(b,e)+f(e+1,d)+w(b,d)\),
因为 \(f(b,d)\le f(b,e)+f(e+1,d)+w(b,d)\),所以得到 \(f(a,d)+f(b,c)\ge f(a,c)+f(b,d)\)。
若 \(b\le e<c\),设 \(p=opt(b,c)\),不妨设 \(p\le e\),第二种 \(p>e\) 的情况同理。
\(f(a,d)+f(b,c)=f(a,e)+f(e+1,d)+w(a,d)+f(b,p)+f(p+1,c)+w(b,c)\),
同样根据归纳假设,\(f(a,d)+f(b,c)\ge f(a,p) + f(p+1,c)+w(b,c)+f(b,e)+f(e+1,d)+w(a,d)\),
根据 \(w\) 的四边形不等式,\(f(a,d)+f(b,c)\ge f(a,p)+f(p+1,c)+w(a,c)+f(b,e)+f(e+1,d)+w(b,d)\),
第三步和上面第三步同理,\(f(a,d)+f(b,c)\ge f(a,c)+f(b,d)\)。
因此 \(f\) 满足四边形不等式。
下证,若 \(f\) 满足四边形不等式,则 \(f\) 满足决策单调性 \(opt(i,j-1)\le opt(i,j)\le opt(i+1,j)\),
设 \(g_i(k,j)=f(i,k)+f(k+1,j)+w(i,j)\),代入并消去相同的项,容易算出,\(g_i(a,d)+g_i(b,c)\ge g_i(a,c)+g_i(b,d)\),即 \(g_i\) 满足四边形不等式。
又因为 \(f(i,j)=\min g_i(k,j)\),因此根据定理 \(1\),容易得到 \(f(i,j)\) 关于 \(j\) 满足决策单调性,即 \(opt(i,j-1)\le opt(i,j)\)。
设 \(h_j(i,k)=f(i,k)+f(k+1,j)+w(i,j)\),类似的,也可以得到 \(h_j\) 满足四边形不等式。
又因为 \(f(i,j)=\min h_j(i,k)\),得到 \(f(i,j)\) 关于 \(i\) 也满足决策单调性,即 \(opt(i,j)\le opt(i+1,j)\)。
证毕。
LGP1880 [NOI1995] 石子合并
含 最大值问题只用取两个端点转移 的证明。
Solution
设 \(f(l,r)\) 表示将 \([l,r]\) 合并的最小代价。
\(f(l,r)=\min\limits_{l\le k<j} f(l,k) + f(k+1,r) + w(l,r)\),\(w\) 是区间和,显然满足四边形不等式和区间包含单调性,直接优化即可。
若要求的是最大值,\(w\) 仍满足反四边形不等式,但是不满足反区间包含单调性,因此不能这样优化。
设 \(g(l,r)\) 表示最大值,下面我们证明 \(g(l,r) = \max\{g(l+1,r),g(l,r-1)\}+w(l,r)\),
假设当前要解决 \(g(l,r)\),设 \(l<q<p<r\),
不妨设 \(w(l,p)\le w(p+1,r)\),另一种情况同理。
若 \(g(l,r)\) 从 \(p\) 转移,\(g(l,p)\) 从 \(q\) 转移,有 \(g_1(l,r)=g(l,q)+g(q+1,p)+w(l,p)+g(p+1,r)+w(l,r)\),
若 \(g(l,r)\) 从 \(q\) 转移,\(g(r,p)\) 从 \(q\) 转移,有 \(g_2(l,r)=g(l,q)+g(q+1,p)+g(p+1,r)+w(q+1,r)+w(l,r)\),
因为 \(w(l,q)\le w(p+1,r)< w(q+1,r)\),因此 \(g_1(l,r)<g_2(l,r)\),所以转移点要尽量靠左。同理可得,另一种情况 \(w(l,q)\ge w(p+1,r)\) 时转移点要尽量靠右。
证毕。
Code
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
using ULL = unsigned long long;
using LD = long double;
using PII = pair<int, int>;
const int N = 205, INF = 2e9;
int n, a[N], f[N][N], g[N][N], opt[N][N];
int main() {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
a[n + i] = a[i];
}
for (int i = 1; i <= n * 2; i++) {
a[i] += a[i - 1];
opt[i][i] = i;
}
for (int len = 2; len <= n; len++) {
for (int l = 1; l + len - 1 <= n * 2; l++) {
int r = l + len - 1;
f[l][r] = INF;
for (int k = opt[l][r - 1]; k <= min(r - 1, opt[l + 1][r]); k++) {
if (f[l][k] + f[k + 1][r] < f[l][r]) {
f[l][r] = f[l][k] + f[k + 1][r];
opt[l][r] = k;
}
}
f[l][r] += a[r] - a[l - 1];
}
}
for (int len = 2; len <= n; len++) {
for (int l = 1; l + len - 1 <= n * 2; l++) {
int r = l + len - 1;
g[l][r] = max(g[l + 1][r], g[l][r - 1]) + a[r] - a[l - 1];
}
}
int mn = INF, mx = -INF;
for (int i = 1; i <= n; i++) {
mn = min(mn, f[i][i + n - 1]);
mx = max(mx, g[i][i + n - 1]);
}
cout << mn << '\n' << mx << '\n';
return 0;
}
声明
本篇学习笔记目的是做个人笔记梳理和记录,一部分证明或理论写在这里不代表是编者原创的,而是经过整理后,加入了自己的想法,更利于自己理解的,读者仅供参考。

浙公网安备 33010602011771号