牛客小白月赛29-B二进制

牛客小白月赛29-B二进制

题目描述:

scimoon 有一个坏掉的计算器,这个计算器仅接受 \(0\sim 2^{20}-1\) 的数

这个计算器只支持一种操作,举个例子,输入一个数 x,这个数会按顺序进行 n 次操作,在第 i 次操作中,有一个操作符 \(op_i\)​ 和一个数 \(a_i\)

如果 \(op_i=1\) 表示这次操作是将数 x 与 \(a_i\)​ 做 与运算

如果 \(op_i=2\) 表示这次操作是将数 x 与 \(a_i\)​ 做 或运算

如果 \(op_i=3\) 表示这次操作是将数 x 与 \(a_i\)​ 做 异或运算

操作过后 x 将会变为运算的结果

scimoon 觉得这个计算器非常地慢,于是他想对这 n 个运算做一些简化,这个艰巨的任务交给了你

具体而言,你的任务是:用不超过 5 次上面的操作,使得对于任何 \(0\le x\le 2^{20}-1\),你的操作的输出与计算器的输出一致

可以证明必然存在解

可能存在多组解,你只需要输出一组可能的解即可

输入描述:

第一行一个整数 n,表示计算器的操作次数

接下来 n 行,每行两个整数 op 与 a ,按顺序描述了每次操作

输出描述:

第一行一个 m,表示你的操作次数

你必须保证你输出的 \(m\le 5\)

接下来 m 行每行仿照输入中 \(op\ a\) 的格式输出每次操作

示例:

输入

1
1 14514

输出

1
1 14514

备注

\(n \leq 5×10^5,1 \leq op \leq 3,0 \leq a \leq 2^{20}−1\)

题解:

位运算是可以有捷径的,分析可以发现,对于一个数位存在如下情况:

  • 与(&)运算对应位为1,原数位不变
  • 与(&)运算对应位为0,原数位为0
  • 或(|)运算对应位为1,原数位为1
  • 或(|)运算对应位为0,原数位不变
  • 异或(^)运算对应位为1,原数位取反
  • 异或(^)运算对应位为0,原数位不变

所以我们只考虑可能改变数位的操作,即如下三种:

  • x&0 = 0
  • x|1 = 1
  • x ^1=!x

因此我们只需要考虑每次操作的数的各个位数,和执行的运算:

  • 与运算,数位为0,之前所有操作无效,只需对该位执行&0操作
  • 或运算,数位为1,之前所有操作无效,只需对该位执行|1操作
  • 异或运算,数位为1,若上一异或位不为1,则执行一次^1操作,否则不执行
代码:
#include <iostream>
#include <cmath>
using namespace std;

int v[21][4];

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    int n;
    cin >> n;
    for(int i = 0; i < n; ++i) {
        int op, w;
        cin >> op >> w;
        for(int j = 0; j <= 20; ++j) {
            if(op == 1 && (w & 1) == 0) {
                v[j][0] = 1;
                v[j][1] = 0;
                v[j][2] = 0;
            }
            else if(op == 2 && w & 1 == 1) {
                v[j][1] = 1;
                v[j][0] = 0;
                v[j][2] = 0;
            }
            else if(op == 3 && w & 1 == 1) {
                if(v[j][2]) v[j][2] = 0;
                else v[j][2] = 1;
            }
            w >>= 1;
        }
    }
    int a = 0, b = 0, c = 0;
    for(int i = 0; i < 20; ++i) {
        if(v[i][0]) continue;
        a += (1 << i);
    }
    for(int i = 0; i < 20; ++i) {
        if(v[i][1]) {
            b += (1 << i);
        }
    }
    for(int i = 0; i < 20; ++i) {
        if(v[i][2]) {
            c += (1 << i);
        }
    }
    printf("3\n1 %d\n2 %d\n3 %d\n", a, b ,c);
    return 0;
}
posted @ 2020-11-15 22:05  落水清心  阅读(134)  评论(0编辑  收藏  举报