Serval and Shift-Shift-Shift
有趣的构造题。
考虑到两个字符串最多有 位不同,而我们最多只能操作一次,不难想到每次操作修改一位,且不影响之前已经操作过的位。
一个数异或 不变,所以可以想到不影响之前操作的位等价于将那些数异或上 。
接着考虑左移和右移如何构造出 ?可以发现左移时,后缀的一段自动补 。右移时,前缀一段自动补 。我们找到两个字符串最靠左的 ,设为 和 。
如果 ,我们从 扫到 ,只要有不同的就通过右移的方式把 点的 挪过去,前缀不变。
如果 ,先左移一次,让 ,然后按照 做。
如果 ,先按照 做,最后只有 和 不同。用 中最靠右的 一直左移直到把这个 点的 推出去即可。
当两个字符串一个全 另一个非全 时无解。
#include <bits/stdc++.h>
using namespace std;
const int N = 2e3 + 5;
int t, n, x, y;
string a, b;
vector<int> ans;
void op(string& s, int k)
{
if (!k) return;
ans.emplace_back(k);
string g;
for (int i = 0; i <= n; i++) g += "0";
for (int i = 1; i <= n; i++)
{
if (i - k >= 1 and i - k <= n) g[i - k] = s[i];
}
for (int i = 1; i <= n; i++)
{
if (g[i] - '0')
{
s[i] = ((s[i] - '0') xor 1) + '0';
}
}
}
void pre()
{
op(a, x - y);
x = y;
}
void solve()
{
for (int i = x + 1; i <= n; i++)
{
if (a[i] != b[i])
{
op(a, -i + x);
}
}
}
void solve2()
{
int lpos = n;
for (int i = n; i >= 1; i--)
{
if (a[i] - '0')
{
lpos = i;
break;
}
}
for (int i = x; i >= 1; i--)
{
if (a[i] != b[i])
{
op(a, lpos - i);
}
}
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> t;
while (t--)
{
cin >> n;
cin >> a >> b;
a = " " + a, b = " " + b;
ans.clear();
x = 0, y = 0;
for (int i = 1; i <= n; i++)
{
if (!x and a[i] == '1') x = i;
if (!y and b[i] == '1') y = i;
}
if (x and !y) cout << "-1\n";
else if (!x and y) cout << "-1\n";
else if (a == b) cout << "0\n";
else
{
if (x > y) pre();
solve();
if (x < y) solve2();
cout << ans.size() << "\n";
for (auto &i : ans) cout << i << " ";
cout << "\n";
}
}
return 0;
}

浙公网安备 33010602011771号