【题解】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;
}
相关推荐
玩镜的码农小师兄11 天前
[从零开始面试算法] (04/100) LeetCode 136. 只出现一次的数字:哈希表与位运算的巅峰对决
c++·算法·leetcode·面试·位运算·hot100
杨小码不BUG21 天前
灯海寻踪:开灯问题的C++精妙解法(洛谷P1161)
c++·算法·数学建模·位运算·浮点数·信奥赛·csp-j/s
Q741_14722 天前
C++ 位运算 高频面试考点 力扣 面试题 17.19. 消失的两个数字 题解 每日一题
c++·算法·leetcode·面试·位运算
Q741_14723 天前
C++ 位运算 高频面试考点 力扣137. 只出现一次的数字 II 题解 每日一题
c++·算法·leetcode·面试·位运算
Q741_1471 个月前
C++ 位运算 高频面试考点 力扣 371. 两整数之和 题解 每日一题
c++·算法·leetcode·面试·位运算
Q741_1471 个月前
C++ 位运算 高频面试考点 力扣 268. 丢失的数字 题解 每日一题
c++·算法·leetcode·面试·位运算
珍珠是蚌的眼泪2 个月前
LeetCode_位运算
leetcode·位运算·异或·韩明距离·数字的补数
源代码•宸2 个月前
Leetcode—2749. 得到整数零需要执行的最少操作数【中等】(__builtin_popcountl)
c++·经验分享·算法·leetcode·位运算
CUC-MenG2 个月前
2025杭电多校第十场 Cut Check Bit、Multiple and Factor 个人题解
数学·dp·位运算·数位dp·根号分治
Q741_1473 个月前
如何判断一个数是 2 的幂 / 3 的幂 / 4 的幂 / n 的幂 位运算 总结和思考 每日一题 C++的题解与思路
开发语言·c++·算法·leetcode·位运算·总结思考