链接:https://ac.nowcoder.com/acm/contest/8564/B
来源:牛客网
题目描述
scimoon 有一个坏掉的计算器,这个计算器仅接受 0\sim 2^{20}-10∼2
20
−1 的数
这个计算器只支持一种操作,举个例子,输入一个数 x,这个数会按顺序进行 n 次操作,在第 i 次操作中,有一个操作符 op_iop
i
和一个数 a_ia
i
如果 op_i=1op
i
=1 表示这次操作是将数 x 与 a_ia
i
做 与运算
如果 op_i=2op
i
=2 表示这次操作是将数 x 与 a_ia
i
做 或运算
如果 op_i=3op
i
=3 表示这次操作是将数 x 与 a_ia
i
做 异或运算
操作过后 x 将会变为运算的结果
scimoon 觉得这个计算器非常地慢,于是他想对这 n 个运算做一些简化,这个艰巨的任务交给了你
具体而言,你的任务是:用不超过 5 次上面的操作,使得对于任何 0\le x\le 2^{20}-10≤x≤2
20
−1,你的操作的输出与计算器的输出一致
可以证明必然存在解
可能存在多组解,你只需要输出一组可能的解即可
输入描述:
第一行一个整数 n,表示计算器的操作次数
接下来 n 行,每行两个整数 op 与 a ,按顺序描述了每次操作
输出描述:
第一行一个 m,表示你的操作次数
你必须保证你输出的 m\le 5m≤5
接下来 m 行每行仿照输入中 op\ aop a 的格式输出每次操作
示例1
输入
复制
1
1 14514
输出
复制
1
1 14514
备注:
n\le 5\times 10^5,1\le op\le 3,0\le a\le 2^{20}-1n≤5×10
5
,1≤op≤3,0≤a≤2
20
−1
我们发现,与运算,或运算,异或运算都是按照位来算的,所以每一位在经历过那么多次运算后,对于具体的每一位,只需要看每一位是如何变化的,然后针对这一位进行具体的操作
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 5e5 + 10;
int op[N], a[N];
int main(){
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i ++){
scanf("%d%d", &op[i], &a[i]);
}
int AND = (1 << 20) - 1;
int OR = 0;
int XOR = 0;
//cout << AND << endl;
for (int i = 0; i < 20; i ++){
int x = 0, y = 1;
for (int j = 1; j <= n; j ++){
int temp = a[j] >> i & 1;
if (op[j] == 1){
x &= temp;
y &= temp;
}
else if (op[j] == 2){
x |= temp;
y |= temp;
}
else if (op[j] == 3){
x ^= temp;
y ^= temp;
}
}
// cout << x << "------" << y << endl;
// cout << i << endl;
if (x == 0 && y == 0) AND -= (1 << i);
// cout << AND << endl;
if (x == 1 && y == 1) OR += (1 << i);
if (x == 1 && y == 0) XOR += (1 << i);
}
int cnt = 0;
if (AND != (1 << 20 - 1)) cnt ++;
if (OR != 0) cnt ++;
if (XOR != 0) cnt ++;
cout << cnt << endl;
if (AND != (1 << 20 - 1)) cout << "1 " << AND << endl;
if (OR != 0) cout << "2 "<< OR << endl;
if (XOR != 0) cout << "3 "<< XOR << endl;
return 0;
}