【题解】CF2077B Finding OR Sum

本文发布于博客园和洛谷,若您在其他平台阅读到此文,请前往博客园获得更好的阅读体验。

跳转链接:https://www.cnblogs.com/TianTianChaoFangDe/p/18771334。

思路

关于此题,我们首先对 \(n | x\) 变一下形,\(n | x = n + (x \& \sim n)\),也就是把 \(n\) 和 \(x\) 同时为 \(1\) 的位在 \(x\) 中删掉,这样的话,为 \(1\) 的位要么在 \(n\),要么在 \(x\),因此我们可以得出 \((x \& \sim n) + (y \& \sim n) = (n | x) + (n | y) - 2 \times n\)。

我们要得到 \((m | x) + (m | y)\) 的值,只需要把每一位上 \(x\) 和 \(y\) 的 \(1\) 的出现数量情况找出来,再根据 \(m\) 的每一位是 \(1\) 还是 \(0\) 来模拟或运算以及位运算即可。

那么我们如何在两次询问的情况下,把每一位的 \(1\) 的出现数量找出来呢?

我们注意到,在二进制位的情况下相加,当前位为第 \(i\) 位,如果第 \(i + 1\) 位和 \(i - 1\) 位都是 \(0\),则两个数的第 \(i\) 位相加只会有这两种情况:

  • 两个 \(1\):第 \(i + 1\) 位为 \(1\),第 \(i\) 位为 \(0\)。
  • 两个 \(0\):第 \(i + 1\) 位和 第 \(i\) 位均为 \(0\)。
  • 一个 \(1\) 一个 \(0\):第 \(i\) 位为 \(1\),第 \(i + 1\) 位为 \(0\)。

那么,我们就可以根据上面那个式子,求一次奇数位全部变成 \(0\) 的两个数的和,把偶数位的 \(1\) 的出现次数情况求出来,求一次偶数位全部变成 \(0\) 的两个数的和,把奇数位的 \(1\) 的出现次数情况求出来。

然后,根据下面的规则逐位求解:

  • 如果 \(m\) 第 \(i\) 位为 \(1\),那么这一位对答案的贡献就是 \(1 \ll (i + 1)\)。
  • 如果 \(m\) 第 \(i\) 位为 \(0\),那么这一位对答案的贡献就看 \(1\) 的出现次数,如果出现次数为 \(2\),那就是 \(1 \ll (i + 1)\),如果出现次数为 \(1\),那就是 \(1 \ll i\)。

AC CODE

cpp 复制代码
#include <bits/stdc++.h>
#define inf 2e18
#define int long long

const int N = 2e5 + 9;

int ask(int x) {
    std::cout << x << std::endl;
    int op;std::cin >> op;
    return op;
}

void solve()
{
    std::vector<int> a(30);

    int tmp = 0;
    for(int i = 0;i < 30;i += 2) {
        tmp |= (1ll << i);
    }
    
    int res1 = ask(tmp) - tmp * 2;
    for(int i = 1;i < 30;i += 2) {
        if(res1 & (1ll << (i + 1))) {
            a[i] = 2;
        } else if(res1 & (1ll << i)) {
            a[i] = 1;
        } else {
            a[i] = 0;
        }
    }

    tmp = 0;
    for(int i = 1;i < 30;i += 2) {
        tmp |= (1ll << i);
    }

    int res2 = ask(tmp) - tmp * 2;
    for(int i = 0;i < 30;i += 2) {
        if(res2 & (1ll << (i + 1))) {
            a[i] = 2;
        } else if(res2 & (1ll << i)) {
            a[i] = 1;
        } else {
            a[i] = 0;
        }
    }

    std::cout << '!' << std::endl;

    int ck;std::cin >> ck;

    int ans = 0;
    for(int i = 0;i < 30;i ++) {
        if(ck & (1 << i)) {
            ans += (1ll << (i + 1));
        } else if(a[i] == 2) {
            ans += (1ll << (i + 1));
        } else if(a[i] == 1) {
            ans += (1ll << i);
        }
    }

    std::cout << ans << std::endl;
}
相关推荐
Logic1013 天前
C语言/数据结构位运算题解:异或XOR找出套碗游戏中的“幸运碗“——只出现一次的数字
c语言·数据结构·算法·数组·位运算·时间复杂度·空间复杂度
Logic1016 天前
C语言/数据结构位运算题解:异或XOR找出优秀项目组中的“独特编号“——只出现一次的数字
c语言·数据结构·数组·位运算·时间复杂度·算法题·异或性质
Logic1018 天前
C语言/数据结构位运算题解:异或XOR找出英雄队伍中的“独特战斗力“——只出现一次的数字
c语言·数据结构·数组·位运算·时间复杂度·算法题·异或性质
Logic10113 天前
C语言/数据结构位运算题解:异或XOR找出学习计划中的“独特学习时间“——只出现一次的数字
c语言·数据结构·数组·位运算·时间复杂度·算法题·异或性质
Logic10114 天前
C语言/数据结构位运算题解:异或XOR找出弹子游戏机中数量为奇数的数字——只出现奇数次
c语言·数据结构·数组·位运算·时间复杂度·算法题·异或性质
Logic10115 天前
C语言/数据结构位运算题解:异或XOR找出书柜中编号只出现一次的那一层——只出现一次的数字
c语言·数据结构·数组·位运算·时间复杂度·算法题·异或性质
Logic10115 天前
C语言/数据结构位运算题解:异或XOR找出星球探险中的“独特能量石“——只出现一次的数字
c语言·数据结构·数组·位运算·时间复杂度·算法题·异或性质
Logic10116 天前
C语言/数据结构位运算题解:异或XOR找出多任务下载器中的“独特下载速度“——只出现一次的数字
c语言·数据结构·数组·位运算·时间复杂度·算法题·异或性质
Logic10116 天前
C语言/数据结构位运算题解:异或XOR找出游戏速通中的“独特初始能量值“——只出现一次的数字
c语言·数据结构·数组·位运算·时间复杂度·算法题·异或性质
Logic10123 天前
C语言/数据结构位运算题解:异或XOR找出时尚聚会中的“独特颜色“——只出现一次的数字
c语言·数据结构·数组·位运算·时间复杂度·算法题·异或性质