BD202604 匹配题 题解

BD202604 匹配题

码蹄集OJ-匹配题

Solution

考虑一个包含 \(1\sim n\) 的离散数轴。题目给定的矩阵 \(\{A_{ij}\}\) 可被看作区间 \([i,j]\) 的权值。在完全图 \(K_n\) 中,对于连接顶点 \(i\) 和 \(j\) 的边 \(e_{ij}\)(\(i<j\)),其权值 \(w(i,j)\) 可被分为两部分贡献:所有包含 \(i\) 且不包含 \(j\) 的区间的权值和 与 所有包含 \(j\) 且不包含 \(i\) 的区间权值和。可以证明,存在一个最小权完美匹配,若将其所有边 \(e_{ij}\) 映射到离散数轴上,所有区间 \([i,j]\) 只嵌套或独立,而不交错。于是使用区间 DP 解决,复杂度 \(O(n^3)\),常数较小,可以通过。

证明

记 \(\displaystyle B_i = \sum_{l=1}^{i}\sum_{r=i}^{n}A_{lr}\) 表示所有包含 \(i\) 的区间的权值和,\(\displaystyle C_{ij} = \sum_{l=1}^{i}\sum_{r=j}^{n}A_{lr}\) 表示所有包含 \(i\) 和 \(j\) 的区间的权值和。于是

\[w(i,j) = B_i + B_j - 2 C_{ij} \tag{1}. \]

设 \(a<b<c<d\),我们证明,如果存在一个最小权完美匹配包含 \(e_{ac}\) 和 \(e_{bd}\),那么将这两边替换为 \(e_{ad}\) 和 \(e_{bc}\),所得仍是一个最小权完美匹配。实则证明

\[w(a,c)+w(b,d)-w(a,d)-w(b,c)\ge0.\tag{2} \]

将 \((1)\) 式代入,\(B_i\) 被消掉,转化为

\[C(a,d)+C(b,c)-C(a,c)-C(b,d)\ge0.\tag{3} \]

考虑固定某一区间 \([x,y]\),计算其对 \((3)\) 式的贡献系数:

\[\Delta_{xy} = [x\le a][y \ge d] + [x \le b][y \ge c] - [x \le a][y \ge c] - [x\le b][y \ge d]. \tag{4} \]

显然 \(\Delta_{xy} \ge 0\),于是

\[\text{LHS}_{(3)} = \sum_{[l,r] \subset [1,n]} \Delta_{lr} A_{lr} \ge 0. \tag{5} \]

证讫。

关于 DP

设 \(dp[i][j]\) 表示只考虑区间 \([i,j]\) 内的点的完美匹配最小权。

由于区间间关系只有不交和嵌套,可列出转移方程

\[dp[i][j] = \min\begin{cases}dp[i+1][j-1]+w(i,j)\\dp[i][k]+dp[k+1][j],\quad 1 \le k < j\end{cases}. \]

边界条件:\(dp[i][i+1] = w(i,i+1)\)。

要保证处理的区间长度总是偶数。

Reflection

  • 矩阵和区间的联系
  • 四边形不等式,矩阵的 Monge 性质,区间的次模性

Code

#include <bits/stdc++.h>
#define vi vector<int>
#define vl vector<long long>
#define vii vector<int>::iterator
#define vli vector<long long>::iterator
#define pii pair<int, int>
#define pll pair<long long, long long>
#define mkp make_pair
#define inc(i,a,b) for(auto i=(a);i<=(b);++i)
#define dec(i,a,b) for(auto i=(a);i>=(b);--i)
#define lbd lower_bound
#define ubd upper_bound
#define prt(a) for(auto i:a)cout<<i<<' ';cout<<'\n';

#ifdef __SIZEOF_INT128__
typedef __int128 i128;
typedef unsigned __int128 u128;
#endif
typedef long long i64;
typedef unsigned long long u64;
typedef unsigned u32;

const u32 MG_NR = 0x9e3779b9u;
const int MAXN = 1500;

using namespace std;

array<array<i64, MAXN + 2>, MAXN + 2> a, s, w, dp;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n; cin >> n;
    inc(i, 1, n) inc(j, i, n)
        cin >> a[i][j];
    inc(i, 1, n) inc(j, 1, n)
        s[i][j] = s[i - 1][j] + a[i][j];
    inc(i, 1, n) inc(j, 1, n)
        s[i][j] += s[i][j - 1];
    inc(i, 1, n) inc(j, i, n)
        w[i][j] = s[i][j - 1] - s[i][i - 1] + s[j][n] + s[i][j - 1] - s[i][n] - s[j][j - 1];
    for (int i = 2; i <= n; i += 2) {
        for (int j = 1; j + i - 1 <= n; ++j) {
            if (i == 2) { dp[j][j + i - 1] = w[j][j + i - 1]; continue; }
            dp[j][j + i - 1] = dp[j + 1][j + i - 2] + w[j][j + i - 1];
            for (int k = j + 1; k < j + i - 1; k += 2) {
                dp[j][j + i - 1] = min(dp[j][j + i - 1], dp[j][k] + dp[k + 1][j + i - 1]);
            }
        }
    }
    cout << dp[1][n] << '\n';
    return 0;
}
posted @ 2026-10-01 21:46  SHUddol  阅读(3)  评论(0)    收藏  举报