[ARC176E] Max Vector

转化题意

你需要找出两个序列 \(x,y\),在满足下列条件的情况下最小化 \(\sum (x_i+y_i)\)

  • 对于任意 \(1\leq i\leq N\),满足 \(x_i\geq X_i,y_i\geq Y_i\)

  • 对于任意 \(1\leq i\leq M\),满足 \(\forall j, x_j\geq A_{i,j}\) 或者 \(\forall j, y_j\geq A_{i,j}\)

    注:后面会把对于任意 \(i\) 的条件简写成 \(x\geq A_i\)\(y\geq A_i\)

解题思路

这题是最优化问题,具有无法贪心限制与值域上大小有关数据范围小的特点,我们使用网络流最小割解决。

考虑经典的拆点做法。我们对于每个 \(x_i\) 建出 \(500\) 个点,同时令 \(x_i\) 的第 \(j\) 个点像第 \(j+1\) 个点连一条对应值的边,表示选这个数。当 \(x_i=j\) 的时候就割掉这条边。\(y_i\) 的点要倒着建(为了后面第二个限制)。

对于上述题意的第一个限制,只要把不满足限制的边去掉就行了。

考虑怎么满足第二个限制,形式为“\(x\)\(y\)”这样的限制在最小割里难以直接做。我们将条件转化为:当 \(x<A_i\)\(y\geq A_i\);当 \(y<A_i\)\(x\geq A_i\)

继续考虑如何在图上描述这样的限制。我们对每个 \(A_i\) 建立一个点 \(p_i\),连 \(A_i\)\(x\) 中对应的点 \(\to\) \(p_i\) \(\to\) \(A_i+1\)\(y\) 中对应的点,表示 \(x<A_i\)\(y\geq A_i\);反过来也同理。

答案就是最小割。总点数为 \(O(nV)\),其中 \(V\) 是值域。

点击查看代码
#include <bits/stdc++.h>
#include <atcoder/maxflow>
#define FL(i, a, b) for (int i = (a); i <= (b); ++i)
#define FR(i, a, b) for (int i = (a); i >= (b); --i)
using namespace std;
using namespace atcoder;
constexpr int N = 3e5 + 10, M = 3e6 + 10, V = 500;
constexpr int INF = 1e9 + 10;
int n, m, s, t, cnt = 1;
int Id(int i, int j) {
	return (i - 1) * (V + 1) + j;
}
int main() {
	scanf("%d %d", &n, &m);
	s = n * 2 * (V + 1) + m + 1, t = s + 1;
	mf_graph<int> G(t + 1);
	FL(i, 1, n) {
		int x;
		scanf("%d", &x);
		G.add_edge(s, Id(i, x), INF);
		G.add_edge(Id(i, V + 1), t, INF);
		FL(j, 1, V) {
			G.add_edge(Id(i, j), Id(i, j + 1), j);
			G.add_edge(Id(i, j + 1), Id(i, j), INF);
		}
	}
	FL(i, n + 1, n * 2) {
		int x;
		scanf("%d", &x);
		G.add_edge(s, Id(i, 1), INF);
		G.add_edge(Id(i, V + 2 - x), t, INF);
		FL(j, 1, V) {
			G.add_edge(Id(i, j), Id(i, j + 1), V - j + 1);
			G.add_edge(Id(i, j + 1), Id(i, j), INF);
		}
	}
	FL(i, 1, m) {
		FL(j, 1, n) {
			int x;
			scanf("%d", &x);
			G.add_edge(n * 2 * (V + 1) + i, Id(j, x), INF);
			G.add_edge(Id(j + n, V + 2 - x), n * 2 * (V + 1) + i, INF);
		}
	}
	printf("%d\n", G.flow(s, t));
	return 0;
}
posted @ 2025-06-29 21:27  徐子洋  阅读(10)  评论(0)    收藏  举报