zoukankan      html  css  js  c++  java
  • 牛客小白月赛29-B二进制

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

    题目描述:

    scimoon 有一个坏掉的计算器,这个计算器仅接受 (0sim 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 次上面的操作,使得对于任何 (0le xle 2^{20}-1),你的操作的输出与计算器的输出一致

    可以证明必然存在解

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

    输入描述:

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

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

    输出描述:

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

    你必须保证你输出的 (mle 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
    1 %d
    2 %d
    3 %d
    ", a, b ,c);
        return 0;
    }
    
  • 相关阅读:
    不用google 是不行的
    一些主题
    腾讯cdc空间
    断言assert的使用
    malloc()和free()的相关知识
    linux上面的sz,rz命令与ssh的配合
    寻找第k小的元素
    c语言中字符串处理函数
    详解之#ifdef和#ifndef
    搭建测试环境linux静态链接库与动态链接库的区别及动态库的创建
  • 原文地址:https://www.cnblogs.com/LeafLove/p/13982627.html
Copyright © 2011-2022 走看看