D. Serval and Shift-Shift-Shift
D. Serval and Shift-Shift-Shift
Serval has two -bit binary integer numbers and . He wants to share those numbers with Toxel.
Since Toxel likes the number more, Serval decides to change into by some (possibly zero) operations. In an operation, Serval can choose any positive integer between and , and change into one of the following number:
In other words, the operation moves every bit of left or right by positions, where the overflowed bits are removed, and the missing bits are padded with . The bitwise XOR of the shift result and the original is assigned back to .
Serval does not have much time. He wants to perform no more than operations to change into . Please help him to find out an operation sequence, or determine that it is impossible to change into in at most operations. You do not need to minimize the number of operations.
In this problem, denotes the bitwise XOR operation of and . and 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 (). The description of the test cases follows.
The first line of each test case contains a single integer () — the number of bits in numbers and .
The second and the third line of each test case contain a binary string of length , representing and , respectively. The strings contain only characters 0 and 1.
It is guaranteed that the sum of over all test cases does not exceed .
Output
For each test case, if it is impossible to change into in at most operations, print a single integer .
Otherwise, in the first line, print the number of operations ().
If , in the second line, print integers representing the operations. If , it means logical left shift by positions. If , it means logical right shift by 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 into .
The second operation changes into .
The bits with strikethroughs are overflowed bits that are removed. The bits with underline are padded bits.
In the second test case, is already equal to , so no operations are needed.
In the third test case, it can be shown that cannot be changed into .
解题思路
官方给出的题解写得很好,我就按照其思路来写了。
首先当且仅当与均为全和与均不全为才有解。
如果为全,那么很明显不管如何操作始终均为全,因此如果不全为那么无解。
如果不全为,由于每次操作至少左移或者右移一位,因此位移后的结果一定与原串不同,因此异或后的结果一定不为。所以如果为全那么无解。
然后就是与均不全为的情况了,可以证明一定存在一种方案使得在不超过次的操作下让变成。定义为的最低位的的位,为的最高位的的位。这里的高低位与二进制的规则相同,即最左边为最高位,最右边为最低位。然后按照下面的个步骤来进行构造:
- 如果,那么将左移位,然后异或。经过这步操作后(可能没有)一定有。
- 考虑的每一位(注意到此时均为),如果,那么我们将右移位然后异或,那么就能将置成。完成后就会有。
- 如果是的情况,我们将右移位然后异或,使得。
- 考虑的每一位,如果,那么将左移位然后异或,那么就能将置成。完成后就一定会有。
可以发现第步与第步一共最多需要次操作。而第步与第步一定不会同时出现,这是因为如果执行了第步那么一定会有而不用执行第步。因此我们最多使用次操作就可以把变成。
AC代码如下,时间复杂度为:
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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
2022-03-01 糖果传递
2022-03-01 均值不等式证明
2021-03-01 关于C++中构造函数的常见疑问