P8544 「Wdoi-2」禁断之门对面,是此世还是彼世

Part 1. 转换

由于 \(A_{i,j}=a_ib_j\),这个 \(f(B)\) 显然可以化简:

\[\begin{aligned}f(B)&=\sum\limits_{i=1}^{n}\sum\limits_{j=1}^t\sum\limits_{k=\min(B_{i,j},B_{i+1,j})}^{\max(B_{i,j},B_{i+1,j})}A_{i,k}\\&=\sum\limits_{i=1}^n\sum\limits_{j=1}^t\sum\limits_{k=\min(B_{i,j},B_{i+1,j})}^{\max(B_{i,j},B_{i+1,j})}a_ib_k\\&=\sum\limits_{i=1}^na_i\sum\limits_{j=1}^tS_{\max(B_{i,j},B_{i+1,j})}-S_{\min(B_{i,j},B_{i+1,j})-1}\end{aligned} \]

\(S_i\)\(b\) 数组的前缀和。

发现若得到 \(g(B_1,B_2)=\sum\limits_{j=1}^tS_{\max(B_{1,j},B_{2,j})}-S_{\min(B_{1,j},B_{2,j})-1}\) 的最小值,我们可以令 \(B_{2k+1}=B_1,B_{2k+2}=B_2\)。这样显然最优。也就是说,\(f(B)=\left(\sum\limits_{i=1}^na_i\right)\cdot \min g(B_1,B_2)\)

问题转换为找到一个 \(B_1,B_2\),分别满足每个元素两两不同,都在 \([1,m]\) 之间,并且对应的位置上的元素不同,使得 \(g(B_1,B_2)\) 最小。

由于同一行元素两两不同以及值域的限制,考虑转换成匹配问题。相当于现在有两列数(分为左部和右部),分别为 \(1,2,\cdots ,m\),在左部中选择 \(t\) 个数,并和右部的 \(t\) 个数匹配。满足不存在形如 \((i,i)\) 的匹配,一对匹配 \((i,j)\) 的价值就是 \(S_{\max(i,j)}-S_{\min(i,j)-1}\),也就是 \(b_{\min(i,j)}+b_{\min(i,j)+1}+\cdots+b_{\max(i,j)}\)。一组匹配的价值就是每对匹配的价值之和,求钦定有 \(t\) 对匹配的最小匹配

Part 2. 猜想

有个比较感性的想法,就是一对匹配不应该跨过太大的距离。考虑从左到右按顺序匹配,如果匹配跨过了一段空区间,那么不如不跨过这段区间,因为这样减小了代价的同时也给后面的点更多的选择方案。

另一个比较感性的想法,匹配应该尽可能不交叉。这里借用这篇题解的图:

如上图,匹配 \((2,5)(4,3)\) 显然不如匹配 \((2,3),(4,5)\)。即如果存在交叉的匹配,我们尝试交换匹配以减少价值。而且可以发现减少交叉必定不劣。

手玩一些数据之后,我们发现最优解中,\(i\) 只能形成 \((i,j)(j\in \{i-2,i-1,i+1,i+2\})\) 的匹配。我们下面试图证明这个结论。

Part 3. 证明

\(i\) 显然可以和 \(i-1,i+1\) 匹配,即证最优解中合法匹配 \((i,j)\) 满足 \(j-i\le 2\)。下面从左到右考虑一组匹配 \((i,j)(j>i+2)\) 如何调整(小于 \(i\) 的左部点的匹配均满足猜想),\(j<i-2\) 根据对称性同理:

  • \(\exists k\in \{1,2\}\),不存在匹配 \((?,i+k)\)(即右部的 \(i+k\) 没有被匹配),显然将 \((i,j)\) 调整为 \((i,i+k)\) 更优。
  • 否则存在 \((x,i+1),(y,i+2)\) 的匹配,且我们从左到右调整,显然有 \(x,y>i\)\(x\neq y\)。注意到匹配 \((i,j)\)\((x,i+1),(y,i+2)\) 都有上述的交叉,所以我们试图交换两个匹配的右部点以减少交叉:若 \(x=j\),则 \(y\neq j\),将原匹配 \((i,j)(y,i+2)\) 重组为 \((i,i+2)(y,j)\) 即可;若 \(x\neq j\),将原匹配 \((i,j)(x,i+1)\) 重组为 \((i,i+1)(x,j)\) 即可。

这样我们就能够将任意的合法匹配调整为更优的、满足 \(i\) 只能形成 \((i,j)(j\in \{i-2,i-1,i+1,i+2\})\) 的匹配的方案。

最终只剩下三种结构:连续的三元环,例如 \((i,i+1)(i+1,i+2)(i+2,i)\) ;连续的二元环,例如 \((i,i+1)(i+1,i)\);连续的一条链,例如 \((i,i+1)(i+1,i+2)(i+2,i+3)\cdots (i+k,i+k+1)\)。前两种情况有交叉,但是无法调整;并且能够发现,只有前两种情况无法调整。

Part 4. 你会了

然后就能考虑 dp 了:令 \(f_{i,j,0/1}\) 表示目前考虑到 \(i\) 的匹配 \((i,?)\),前 \(i\) 个点一共有 \(j\) 对匹配,目前是否在一条形如 \((u,u+1)(u+1,u+2)\cdots(i-1,i)\) 的链中。

  • \(f_{i,j,1}\gets f_{i-1,j-1,1}+b_{i}+b_{i-1}\),表示延续一条链,增加一对匹配,连接 \((i-1,i)\)
  • \(f_{i,j,1}\gets f_{i-2,j-1,0}+b_i+b_{i-1}\),表示新建一条链,增加一对匹配,连接 \((i-1,i)\)
  • \(f_{i,j,0}\gets f_{i-2,j-2,0}+2(b_i+b_{i-1})\),表示新增一个二元环,增加两对匹配,连接 \((i-1,i)(i,i-1)\)
  • \(f_{i,j,0}\gets f_{i-3,j-3,0}+2b_i+3b_{i-1}+2b_{i-2}\),表示新增一个三元环,增加三对匹配,连接 \((i-2,i-1)(i-1,i)(i,i-2)\) 或者 \((i,i-1)(i-1,i-2),(i-2,i)\)
  • \(f_{i,j,0}\gets f_{i-1,j,0}\),表示 \(i\) 没有匹配任何点。
  • \(f_{i,j,0}\gets f_{i,j,1}\),表示我摆烂了,不延续一条链。

乍一看是 \(O(mt)\) 的?的确是 \(O(mt)\) 的。

考虑瓶颈在于强制选择 \(t\) 对匹配,对于这类问题,我们可以通过证明答案随匹配数的变化具有凸性,而进行 wqs 二分。

这题的凸性十分显然,因为是匹配问题,可以转化成费用流模型:

  • 有超源 \(S'\) 和超汇 \(T'\),源点 \(S\) 和汇点 \(T\)\(S'\to S\) 连流量 \(t\),费用 \(0\) 的边(以下 \(u\to v\) 连流量 \(f\) 费用 \(w\) 的边简记为 \(u\to v(f,w)\))。即 \(S'\to S(t,0),T\to T'(t,0)\)
  • \(i\) 的左部点为 \(l_i\),右部点为 \(r_i\)\(S\to l_i(1,0),r_i\to T(1,0)\)
  • 对于 \(i\neq j\)\(l_i\to r_i(1,S_{\max(i,j)}-S_{\min(i,j)-1})\)

不难发现最小费用最大流就是答案。根据费用流函数的凸性,原问题具有凸性,可以 wqs 二分。具体地,二分斜率 \(k\),新建一对匹配时,直接减去 \(k\) 的代价即可。

最终复杂度 \(O(n\log V)\)。代码好写得很。

// Problem: P8544 「Wdoi-2」禁断之门对面,是此世还是彼世
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P8544
// Memory Limit: 512 MB
// Time Limit: 2500 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define int long long
using namespace std;

namespace vbzIO {
    char ibuf[(1 << 20) + 1], *iS, *iT;
    #if ONLINE_JUDGE
    #define gh() (iS == iT ? iT = (iS = ibuf) + fread(ibuf, 1, (1 << 20) + 1, stdin), (iS == iT ? EOF : *iS++) : *iS++)
    #else
    #define gh() getchar()
    #endif
    #define mt make_tuple
    #define mp make_pair
    #define fi first
    #define se second
    #define pc putchar
    #define pb emplace_back
    #define ins insert
    #define era erase
    typedef tuple<int, int, int> tu3;
    typedef pair<int, int> pi;
    inline int rd() {
        char ch = gh();
        int x = 0;
        bool t = 0;
        while (ch < '0' || ch > '9') t |= ch == '-', ch = gh();
        while (ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + (ch ^ 48), ch = gh();
        return t ? ~(x - 1) : x;
    }
    inline void wr(int x) {
        if (x < 0) x = ~(x - 1), putchar('-');
        if (x > 9) wr(x / 10);
        putchar(x % 10 + '0');
    }
}
using namespace vbzIO;

const int N = 5e5 + 100;
const int P = 1e9 + 7;
const int inf = 1e12;

int n, m, t, sum, b[N];
pi f[N][2];

pi operator + (const pi &lh, const pi &rh) {
    return mp(lh.fi + rh.fi, lh.se + rh.se);
}

pi chk(int w) {
    for (int i = 0; i <= m; i++)
        f[i][0] = f[i][1] = mp(inf, 0);
    f[0][0] = mp(0, 0);
    for (int i = 1; i <= m; i++) {
        f[i][1] = min(f[i][1], f[i - 1][1] + mp(b[i] + b[i - 1] - w, 1));
        if (i >= 2) f[i][1] = min(f[i][1], f[i - 2][0] + mp(b[i] + b[i - 1] - w, 1));
        if (i >= 2) f[i][0] = min(f[i][0], f[i - 2][0] + mp(2 * (b[i] + b[i - 1] - w), 2));
        if (i >= 3) f[i][0] = min(f[i][0], f[i - 3][0] + mp(2 * b[i] + 2 * b[i - 2] + 3 * b[i - 1] - 3 * w, 3));
        f[i][0] = min(min(f[i][0], f[i - 1][0]), f[i][1]);
    }
    return f[m][0];
}

signed main() {
    n = rd(), m = rd(), t = rd();
    for (int i = 1; i <= n; i++) 
        (sum += rd()) %= P;
    for (int i = 1; i <= m; i++) b[i] = rd();
    int l = 0, r = 3e9, res = 0;
    while (l <= r) {
        int mid = (l + r) >> 1;
        if (chk(mid).se <= t) res = mid, l = mid + 1;
        else r = mid - 1;
    }
    wr(((chk(res).fi % P + res * t % P) % P + P) * sum % P);
    return 0;
}
posted @ 2023-09-19 09:37  Ender_32k  阅读(25)  评论(0编辑  收藏  举报