D. Serval and Shift-Shift-Shift
D. Serval and Shift-Shift-Shift
Serval has two $n$-bit binary integer numbers $a$ and $b$. He wants to share those numbers with Toxel.
Since Toxel likes the number $b$ more, Serval decides to change $a$ into $b$ by some (possibly zero) operations. In an operation, Serval can choose any positive integer $k$ between $1$ and $n$, and change $a$ into one of the following number:
- $a\oplus(a\ll k)$
- $a\oplus(a\gg k)$
In other words, the operation moves every bit of $a$ left or right by $k$ positions, where the overflowed bits are removed, and the missing bits are padded with $0$. The bitwise XOR of the shift result and the original $a$ is assigned back to $a$.
Serval does not have much time. He wants to perform no more than $n$ operations to change $a$ into $b$. Please help him to find out an operation sequence, or determine that it is impossible to change $a$ into $b$ in at most $n$ operations. You do not need to minimize the number of operations.
In this problem, $x\oplus y$ denotes the bitwise XOR operation of $x$ and $y$. $a\ll k$ and $a\gg k$ denote the logical left shift and logical right shift.
Input
Each test contains multiple test cases. The first line contains the number of test cases $t$ ($1\le t\le2\cdot10^{3}$). The description of the test cases follows.
The first line of each test case contains a single integer $n$ ($1\le n\le2\cdot10^{3}$) — the number of bits in numbers $a$ and $b$.
The second and the third line of each test case contain a binary string of length $n$, representing $a$ and $b$, respectively. The strings contain only characters 0 and 1.
It is guaranteed that the sum of $n$ over all test cases does not exceed $2\cdot10^{3}$.
Output
For each test case, if it is impossible to change $a$ into $b$ in at most $n$ operations, print a single integer $-1$.
Otherwise, in the first line, print the number of operations $m$ ($0\le m\le n$).
If $m>0$, in the second line, print $m$ integers $k_{1},k_{2},\dots,k_{m}$ representing the operations. If $1\le k_{i}\le n$, it means logical left shift $a$ by $k_{i}$ positions. If $-n\le k_{i}\le-1$, it means logical right shift $a$ by $-k_{i}$ positions.
If there are multiple solutions, print any of them.
Example
input
3 5 00111 11000 1 1 1 3 001 000
output
2 3 -2 0 -1
Note
In the first test case:
The first operation changes $a$ into $\require{cancel}00111\oplus\cancel{001}11\underline{000}=11111$.
The second operation changes $a$ into $\require{cancel}11111\oplus\underline{00}111\cancel{11}=11000$.
The bits with strikethroughs are overflowed bits that are removed. The bits with underline are padded bits.
In the second test case, $a$ is already equal to $b$, so no operations are needed.
In the third test case, it can be shown that $a$ cannot be changed into $b$.
解题思路
官方给出的题解写得很好,我就按照其思路来写了。
首先当且仅当$a$与$b$均为全$0$和$a$与$b$均不全为$0$才有解。
如果$a$为全$0$,那么很明显不管如何操作$a$始终均为全$0$,因此如果$b$不全为$0$那么无解。
如果$a$不全为$0$,由于每次操作至少左移或者右移一位,因此位移后的结果一定与原串不同,因此异或后的结果一定不为$0$。所以如果$b$为全$0$那么无解。
然后就是$a$与$b$均不全为$0$的情况了,可以证明一定存在一种方案使得在不超过$n$次的操作下让$a$变成$b$。定义$\text{lb}(a)$为$a$的最低位的$1$的位,$\text{hb}(a)$为$a$的最高位的$1$的位。这里的高低位与二进制的规则相同,即最左边为最高位,最右边为最低位。然后按照下面的$4$个步骤来进行构造:
- 如果$\text{hb}(a)<\text{lb}(b)$,那么将$a$左移$\text{lb}(b)-\text{hb}(a)$位,然后异或。经过这步操作后(可能没有)一定有$\text{hb}(a)\geq\text{lb}(b)$。
- 考虑$\text{lb}(b)-1,\text{lb}(b)-2,\dots,1$的每一位$i$(注意到此时$b_i$均为$0$),如果$a_i = 1$,那么我们将$a$右移$\text{hb}(a)-i$位然后异或,那么就能将$a_i$置成$0$。完成后就会有$\text{lb}(a)\ge\text{lb}(b)$。
- 如果是$\text{lb}(a)>\text{lb}(b)$的情况,我们将$a$右移$\text{lb}(a)-\text{lb}(b)$位然后异或,使得$\text{lb}(a)=\text{lb}(b)$。
- 考虑$\text{lb}(b)+1,\text{lb}(b)+2,\dots,n$的每一位$i$,如果$a_i \ne b_i$,那么将$a$左移$i-\text{lb}(a)$位然后异或,那么就能将$a_i$置成$b_i$。完成后就一定会有$a = b$。
可以发现第$2$步与第$4$步一共最多需要$n-1$次操作。而第$1$步与第$3$步一定不会同时出现,这是因为如果执行了第$1$步那么一定会有$\text{lb}(a)=\text{lb}(b)$而不用执行第$3$步。因此我们最多使用$n$次操作就可以把$a$变成$b$。
AC代码如下,时间复杂度为$O(n^2)$:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int N = 2e3 + 10; 5 6 char sa[N], sb[N]; 7 int a[N], b[N]; 8 9 void solve() { 10 int n; 11 scanf("%d %s %s", &n, sa, sb); 12 if (!strcmp(sa, sb)) { // a和b相等 13 printf("0\n"); 14 return; 15 } 16 int ha = n, lb = -1; 17 for (int i = 0; i < n; i++) { 18 a[i] = sa[i] - '0'; 19 if (a[i] && ha == n) ha = i; 20 } 21 for (int i = 0; i < n; i++) { 22 b[i] = sb[i] - '0'; 23 if (b[i]) lb = i; 24 } 25 if (ha == n || lb == -1) { // a或b有一个全为0,无解 26 printf("-1\n"); 27 return; 28 } 29 vector<int> ans; 30 if (ha > lb) { 31 int d = ha - lb; // 将a左移ha-lb位 32 for (int i = lb; i + d < n; i++) { 33 a[i] ^= a[i + d]; 34 } 35 ha = lb; // a的最高位变成了lb 36 ans.push_back(d); 37 } 38 for (int i = lb + 1; i < n; i++) { // 在lb+1...n-1位中把a[i]为1的位变成0 39 if (a[i]) { 40 int d = i - ha; // 右移i-ha位 41 for (int j = n - 1; j >= i; j--) { 42 a[j] ^= a[j - d]; 43 } 44 ans.push_back(-d); 45 } 46 } 47 int la; // 求a的最低位的1 48 for (int i = lb; i >= 0; i--) { 49 if (a[i]) { 50 la = i; 51 break; 52 } 53 } 54 if (la < lb) { 55 int d = lb - la; // 通过把a右移lb-la位使得la=lb 56 for (int i = lb; i - d >= 0; i--) { 57 a[i] ^= a[i - d]; 58 } 59 ans.push_back(-d); 60 } 61 for (int i = lb - 1; i >= 0; i--) { // 在0...lb-1位中把a[i]!=b[i]的位变成b[i] 62 if (a[i] != b[i]) { 63 int d = lb - i; // 左移lb-i位 64 for (int j = 0; j <= i; j++) { 65 a[j] ^= a[j + d]; 66 } 67 ans.push_back(d); 68 } 69 } 70 printf("%d\n", ans.size()); 71 for (auto &x : ans) { 72 printf("%d ", x); 73 } 74 printf("\n"); 75 } 76 77 int main() { 78 int t; 79 scanf("%d", &t); 80 while (t--) { 81 solve(); 82 } 83 84 return 0; 85 }
参考资料
Codeforces Round #853 (Div. 2) Editorial:https://codeforces.com/blog/entry/113246
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/17169787.html