学习笔记:决策单调性优化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;
}

声明

本篇学习笔记目的是做个人笔记梳理和记录,一部分证明或理论写在这里不代表是编者原创的,而是经过整理后,加入了自己的想法,更利于自己理解的,读者仅供参考。

参考文章

posted @ 2025-02-24 16:23  chenwenmo  阅读(110)  评论(3)    收藏  举报