BD202604 匹配题 题解
BD202604 匹配题
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\) 的区间的权值和。于是
设 \(a<b<c<d\),我们证明,如果存在一个最小权完美匹配包含 \(e_{ac}\) 和 \(e_{bd}\),那么将这两边替换为 \(e_{ad}\) 和 \(e_{bc}\),所得仍是一个最小权完美匹配。实则证明
将 \((1)\) 式代入,\(B_i\) 被消掉,转化为
考虑固定某一区间 \([x,y]\),计算其对 \((3)\) 式的贡献系数:
显然 \(\Delta_{xy} \ge 0\),于是
证讫。
关于 DP
设 \(dp[i][j]\) 表示只考虑区间 \([i,j]\) 内的点的完美匹配最小权。
由于区间间关系只有不交和嵌套,可列出转移方程
边界条件:\(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;
}

浙公网安备 33010602011771号