B. Bitwise Reversion
问题描述
给定三个非负整数 。判断是否存在三个非负整数 满足以下三个条件:
其中 表示按位与操作。
解题思路
问题要求我们根据 两两按位与操作的结果,判断是否存在这样的三个非负整数 。
我们来分析按位与操作对 施加的约束。
- 条件 意味着,对于任何一个比特位,如果该位在 中为 1,那么它在 和 中也必须为 1。
- 同样地, 意味着,在 中为 1 的任何比特位,在 和 中也必须为 1。
- 而 意味着,在 中为 1 的任何比特位,在 和 中也必须为 1。
从这些观察中,我们可以确定在 中必须为 1 的最小比特集合。
- 对于 ,它必须包含所有在 中为 1 的比特位和所有在 中为 1 的比特位。满足此条件的最小整数是 。
- 对于 ,它必须包含所有来自 和 的比特位。最小的整数是 。
- 对于 ,它必须包含所有来自 和 的比特位。最小的整数是 。
这给了我们一个可能的候选解。我们尝试这样构造 :
- 令
- 令
- 令
这个构造给了我们 可能的“最小”值。如果存在其他整数 构成一个有效的解,那么必须满足 是 的子掩码, 是 的子掩码, 是 的子掩码。然而,向 中添加更多的比特位(即将 0 变为 1)只会导致与操作的结果保持不变或从 0 变为 1,绝不会将 1 变为 0。这意味着,如果我们最小的构造 (a & b) 的结果中有一个不在 x 中的比特位,那么没有更大的 a 或 b 值可以修复它。
因此,如果这个最小的构造可行,解就存在。如果它失败了,那么解就不存在。策略是构造这些 的候选值,然后验证它们是否满足最初的三个方程。
算法如下:
- 计算候选值:
a = x | z,b = x | y,c = y | z。 - 检查它们是否满足条件:
(a & b) == x(b & c) == y(c & a) == z
- 如果所有三个条件都为真,答案是 “YES”。否则,是 “NO”。
查看代码
#include <algorithm>
#include <cmath>
#include <cstdint>
#include <iostream>
#include <map>
#include <numeric>
#include <set>
#include <tuple>
#include <vector>
using namespace std;
#define int long long
// #define mod 1000000007
#define N 500005
void solve() {
int x, y, z;
cin >> x >> y >> z;
int a = x | z;
int b = x | y;
int c = y | z;
if ((a & b) == x && (b & c) == y && (c & a) == z){
cout << "YES" << endl;
}else{
cout << "NO" << endl;
}
}
int32_t main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
#ifdef DEBUG
freopen("./input.txt", "r", stdin);
#endif
int t;
cin >> t;
while (t--) {
#ifdef DEBUG
static int test_num = 1;
cout << "test case: " << test_num++ << endl;
#endif
solve();
}
}