AT ARC193D Magnets
cnblogs。
考虑刻画这个向中靠齐的操作。
发现操作完后其实元素的相对顺序基本不会改变,唯一的变化就是
那么就相当于是
为了放止一些越界问题,可以考虑在操作前在序列头尾各放一个不会影响的
那么就可以把操作刻画成:在序列头尾各放上一个
但是直接考虑合并成
此时就不用考虑每次操作时放
因为每次合并是
于是再对 check 进行转换:把
首先考虑调整,
于是考虑以下 check:
- 按顺序由
1\to n 遍历b_i 。 - 对于
b_i = 1 ,一直扩张直到区间中含有1 。 - 对于
b_i = 0 ,缩成一段考虑,这是因为0 对1 是完全不可的态度。
所以对于长度为m 的段,一直扩张之前的段直到接下来a 中存在长度为m 的全0 段,选掉这个全0 段。
此时就应该有了
考虑答案的下界,
那么会发现,对于
也就是说,
同样的,
所以只需要代入
#include <bits/stdc++.h>
int ans;
inline void check(int k, std::vector<int> a, std::vector<int> b) {
a.insert(a.begin(), k, 0), a.insert(a.end(), k, 0);
const int n = (int)a.size(), m = (int)b.size();
std::vector<std::pair<int, int> > pb;
for (int l = 0, r = 0; l < m; l = r) {
if (b[l] == 1) {
pb.emplace_back(1, 1);
r++; continue;
}
while (r < m && b[r] == 0) r++;
pb.emplace_back(0, r - l);
}
std::vector<int> pre(n);
pre[0] = a[0];
for (int i = 1; i < n; i++) {
pre[i] = pre[i - 1] + a[i];
}
int i = -1;
for (auto [op, len] : pb) {
if (op == 0) {
while (true) {
if (i >= n - len) return ;
if (pre[i + len] - (i == -1 ? 0 : pre[i]) == 0) break;
i += 2;
}
i += len;
}
if (op == 1) {
int j = i + 1;
while (j < n && a[j] == 0) j++;
i = j + (std::abs(i) % 2 == j % 2);
if (i > n) return ;
}
}
ans = k;
}
inline void solve() {
int n; scanf("%d", &n);
std::vector<int> a(n), b(n);
for (int &x : a) scanf("%1d", &x);
for (int &x : b) scanf("%1d", &x);
int pa = 0, pb = 0, sa = n - 1, sb = n - 1;
while (! a[pa]) pa++;
while (! a[sa]) sa--;
while (! b[pb]) pb++;
while (! b[sb]) sb--;
ans = -1;
const int low = std::max({pb - pa, sa - sb, 0});
check(low + 1, a, b);
check(low, a, b);
printf("%d\n", ans);
}
int main() {
int t; scanf("%d", &t);
while (t--) solve();
return 0;
}