【题解】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;
}
相关推荐
汀、人工智能3 天前
[特殊字符] 第79课:分割等和子集
数据结构·算法·数据库架构·位运算·哈希表·分割等和子集
汀、人工智能6 天前
03 - 运算符
数据结构·算法·数据库架构·位运算·哈希表·03 - 运算符
We་ct6 天前
LeetCode 137. 只出现一次的数字 II:从基础到最优的两种解法详解
前端·数据结构·算法·leetcode·typescript·位运算
汉克老师7 天前
GESP2024年12月认证C++三级( 第一部分选择题(9-15))
c++·字符串·位运算·进制·补码·gesp三级·gesp3级
We་ct7 天前
LeetCode 136. 只出现一次的数字:线性时间+常量空间最优解拆解
前端·算法·leetcode·typescript·位运算
汉克老师11 天前
GESP2025年6月认证C++三级( 第一部分选择题(9-15))
c++·字符串·位运算·gesp三级·gesp3级
旖-旎13 天前
位运算(只出现一次的数字|||)(5)
c++·算法·leetcode·位运算
旖-旎14 天前
位运算(两整数之和)(3)
c++·算法·leetcode·位运算
旖-旎15 天前
位运算(判断字符是否唯一)(1)
c++·算法·leetcode·位运算
俩娃妈教编程1 个月前
C++基础知识点:位运算
java·开发语言·jvm·c++·位运算