AcWing 3764. 三元数异或
题目:
如果一个整数,其各个数位不包含 0,1,2 以外的数字,则称这个数为三元数。
例如,1022,11,21,2002 都是三元数。
给定一个可能很长的三元数 x,其首位数字(最左边那位)保证为 2,其他位数字为 0 或 1 或 2。
我们规定,两个长度为 n 的三元数 a 和 b 可以通过三元异或运算 ⊙ 得到另一个长度为 n 的三元数 c。
设 ai,bi,ci 分别表示 a,b,c 的第 i 位的数字,则 ci=(ai+bi)mod3。
例如,10222 ⊙ 11021=21210。
你的任务是对于每个给定的 x,求出可以满足 a ⊙ b=x,并且 max(a,b) 尽可能小的 a,b。
注意,a,b 都必须是 n 位三元数,且不含前导 0。
输入格式
第一行包含整数 T,表示共有 T 组测试数据。
每组数据第一行包含整数 n,表示 x 的长度。
第二行包含一个长度为 n,首位为 2 的三元数 x。
输出格式
每组数据输出占两行,分别包含数 a 和数 b。
如果答案不唯一,则输出任意合理答案均可。
数据范围
1≤T≤104,
1≤n≤5×104,
同一测试点所有 n 的和不超过 5×104。
输入样例:
4
5
22222
5
21211
1
2
9
220222021
输出样例:
11111
11111
11000
10211
1
1
110111011
110111010
思路:
1. 给出三元数c, 求满足条件的三元数 a,b
2. 三元异或运算 a ⊙ b = (a+b)%3;
3. 使a ⊙ b==c 且满足max(a,b)尽可能的小,意思是a,b中的最大值要在所有满足条件的答案中较小
4. 三元数定义:一个整数,其各个数位不包含 0,1,2 以外的数字,则称这个数为三元数
分析三元数的每一位可以由哪两个数经过三元异或运算得出:
①.0可以由(0,0)、(1,2)
②.1可以由(0,1)、(2,2)
③.2可以由(0,2)、(1,1)经过三元异或运算得出
又因为需要满足max(a,b)的结果尽可能小,则a和b中的较大值要尽可能的小,故用贪心
代码:
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
const int N = 5e4+5;
char a[N], b[N], c[N];
int main()
{
int T;
cin>>T;
while (T--)
{
int n, i;
cin>>n;
memset(a,0,sizeof(char)*n);
memset(b,0,sizeof(char)*n);
memset(c,0,sizeof(char)*n);
cin>>c;
a[0] = b[0] = '1';//c的首位数一定为2,那么a和b的首位一定为1
int isBMax = 0;//标记当前b是否已经比a大
for (i = 1; i < n; i++)
if(c[i] == '0')//0,0
a[i] = b[i] = '0';
else if (c[i] == '1')//0,1
{
if (isBMax)//如果当前b已经为a,b中较大值,则只需要令b在满足条件的答案中不再继续变大即可
a[i] = '1', b[i] = '0';
else
a[i] = '0', b[i] = '1';
isBMax = 1;//标记当前b已经为a,b中的较大值
}
else if (c[i] == '2')//0,2 1,1
if (isBMax)//如果当前b已经为a,b中较大值,则只需要令b在满足条件的答案中不再继续变大即可
a[i] = '2', b[i] = '0';
else
a[i] = b[i] = '1';
a[n] = b[n] = '\0';//添上结尾符
cout<<a<<endl<<b<<endl;//输出a,b
}
return 0;
}