[AGC056C] 01 Balanced 题解
[AGC056C] 01 Balanced 题解
有点巧妙这个题。
看到的第一反应是通过前缀和限制条件,限制区间内 0/1 的个数为一个定值且相邻两个数之间的差值 \(\le 1\)。那这个问题看上去可以通过差分约束来做,但由于有负权边要用 SPFA,时间复杂度会炸掉并且第二个条件也不好限制。
考虑换一种思路。我们记 \(x_i\) 表示区间 \(1\sim i\) 中 0 和 1 个数的差值。这样一来限制条件变成了 \(x_{l-1}=x_{r}\) 且 \(|x_i-x_{i-1}|=1\)。首个条件用并查集缩起来即可,第二个条件我们拆成 \(x_i-x_{i-1}\le1\) 且 \(x_{i-1}-x_i\le 1\) 用边权为 \(1\) 的差分 BFS 来维护。对于求字典序最小,实际上就是要 \(x\) 序列的字典序最大,那 BFS 过程中一定取到的是满足条件下的最大值,也实际上满足了字典序的限制。
那对于 \(x_i=x_{i-1}\) 的情况又该如何处理?实际上由于缩起来的所有点奇偶性一定相同,而相邻点之间边权为 \(1\),那这个东西实际上构成了一个二分图,不可能出现 \(x_i=x_{i-1}\) 的情形。
代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
int n, m;
int fa[N];
int fnd(int x) {
return x == fa[x] ? x : fa[x] = fnd(fa[x]);
}
void mge(int x, int y) {
x = fnd(x), y = fnd(y);
if (x ^ y) fa[x] = y;
}
vector<pair<int, int>>v[N];
int dis[N];
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> m;
iota(fa + 1, fa + 1 + n, 1);
for (int i = 0; i < m; i++) {
int x, y;
cin >> x >> y;
--x;
mge(x, y);
}
for (int i = 1; i <= n; i++) {
v[fnd(i)].emplace_back(fnd(i - 1), 1);
v[fnd(i - 1)].emplace_back(fnd(i), 1);
}
memset(dis, 0x3f, sizeof dis);
dis[fnd(0)] = 0;
queue<int>q;
q.push(fnd(0));
while (!q.empty()) {
int x = q.front();
q.pop();
for (auto p : v[x]) {
int y = p.first, w = p.second;
if (dis[y] > 1e9) dis[y] = dis[x] + w, q.push(y);
}
}
for (int i = 0; i < n; i++) {
if (dis[fnd(i)] < dis[fnd(i + 1)]) cout << "0";
else cout << "1";
}
cout << '\n';
return 0;
}

浙公网安备 33010602011771号