CodeForces 1237H Balanced Reversals

发布时间 2024-01-10 15:12:33作者: zltzlt

洛谷传送门

CF 传送门

容易想到把 \(s, t\) 分成长度为 \(2\) 的段考虑。容易发现 \(00, 11\) 的个数在操作过程中不会改变,所以若两串的 \(00\)\(11\) 个数不相等则无解。

考虑依次对 \(i = 2, 4, \ldots, n\) 构造 \(s[1 : i] = t[n - i + 1 : n]\)。对于 \(s_{j - 1}s_j = yx\),依次操作 \(j - 2, j\) 可以把 \(s\) 变成 \(xy s_1 s_2 \ldots s_{j - 2}\)

但是上面的方法只在 \(s\)\(01\) 数量等于 \(t\)\(10\) 数量有效。设 \(f(s)\)\(s\)\(01\) 数量减 \(10\) 数量的值,我们的目标是让 \(f(s) = -f(t)\)。那么若 \(|f(s)| \ge |f(t)|\),一定可以找到 \(s\) 的一个前缀,使得翻转它后 \(f(s) = -f(t)\)。因为 \(f(s)\) 对于 \(s\) 的每个前缀一定 \(+1, -1\) 或不变,因此 \(0 \sim |f(s)|\) 的每个数(或其相反数)都能经过。若 \(|f(s)| < |f(t)|\),反过来,一定可以找到 \(t\) 的一个前缀,使得翻转它后 \(f(s) = -f(t)\)。可以全部操作完后再翻转达到翻转 \(t\) 的前缀的效果。

操作次数为 \(n + 1\)。时间复杂度 \(O(n^2)\)

code
// Problem: H. Balanced Reversals
// Contest: Codeforces - Codeforces Global Round 5
// URL: https://codeforces.com/problemset/problem/1237/H
// Memory Limit: 512 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 4040;

int n;
char s[maxn], t[maxn];

void solve() {
	scanf("%s%s", s + 1, t + 1);
	n = strlen(s + 1);
	int c0 = 0, c1 = 0;
	for (int i = 1; i < n; i += 2) {
		c0 += (s[i] == '0' && s[i + 1] == '0');
		c0 -= (t[i] == '0' && t[i + 1] == '0');
		c1 += (s[i] == '1' && s[i + 1] == '1');
		c1 -= (t[i] == '1' && t[i + 1] == '1');
	}
	if (c0 || c1) {
		puts("-1");
		return;
	}
	int s1 = 0, s2 = 0;
	for (int i = 1; i < n; i += 2) {
		if (s[i] == '0' && s[i + 1] == '1') {
			++s1;
		} else if (s[i] == '1' && s[i + 1] == '0') {
			--s1;
		}
		if (t[i] == '0' && t[i + 1] == '1') {
			++s2;
		} else if (t[i] == '1' && t[i + 1] == '0') {
			--s2;
		}
	}
	vector<int> ans;
	int p = -1;
	if (abs(s1) >= abs(s2) && s1 != -s2) {
		for (int i = 2; i <= n; i += 2) {
			if (s[i - 1] == '0' && s[i] == '1') {
				s1 -= 2;
			} else if (s[i - 1] == '1' && s[i] == '0') {
				s1 += 2;
			}
			if (s1 == -s2) {
				ans.pb(i);
				reverse(s + 1, s + i + 1);
				break;
			}
		}
	} else if (s1 != -s2) {
		for (int i = 2; i <= n; i += 2) {
			if (t[i - 1] == '0' && t[i] == '1') {
				s2 -= 2;
			} else if (t[i - 1] == '1' && t[i] == '0') {
				s2 += 2;
			}
			if (s1 == -s2) {
				p = i;
				reverse(t + 1, t + i + 1);
				break;
			}
		}
	}
	for (int i = 2, j = n; i <= n; i += 2, j -= 2) {
		for (int k = i; k <= n; k += 2) {
			if (s[k - 1] == t[j] && s[k] == t[j - 1]) {
				if (k > 2) {
					reverse(s + 1, s + k - 1);
					ans.pb(k - 2);
				}
				reverse(s + 1, s + k + 1);
				ans.pb(k);
				break;
			}
		}
	}
	if (p != -1) {
		ans.pb(p);
	}
	printf("%d\n", (int)ans.size());
	for (int i : ans) {
		printf("%d ", i);
	}
	putchar('\n');
}

int main() {
	int T = 1;
	scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}