CF2078E. Finding OR Sum
Finding OR Sum
题面
这是一个交互式问题。
有两个隐藏的非负整数 \( x \) 和 \( y \)(\( 0 \leq x, y < 2^{30} \))。你最多可以提出 2 次以下形式的查询。
- 选择一个非负整数 \( n \)(\( 0 \leq n < 2^{30} \))。裁判将返回 \( (n \mid x) + (n \mid y) \) 的值,其中 \(\mid\) 表示按位或操作。
之后,裁判将给你另一个非负整数 \( m \)(\( 0 \leq m < 2^{30} \))。你必须回答 \( (m \mid x) + (m \mid y) \) 的正确值。
思路
首先我们一定会询问一个 0, 令返回的值为 \(A = (0|x) + (0|y) = x + y\).
考虑接下来我们会询问什么数. 由于我们需要算出 \((m|x) + (m|y)\) 的值, 所以我们需要知道 \(x, y\) 在哪些位上是 0, 哪些位上是 1.
于是思考这样一个过程: 我们询问一个数, 其二进制中只有偶数位为 1 \((\)形如 ...1010\()\), 那么必然会返回一个数 \(B\). 将 \(B\) 减去 \(A\), 也就是 \(B - A = - (x + y) = ((n|x) - x) + ((n|y) - y)\), 这样我们就可以对 \(x, y\) 的偶数位进行分析了.
具体的, 我们对于 \(B - A\) 中的每一个偶数位 \(i\) 进行分讨
- 如果 \(x, y\) 在第 \(i\) 位上都是 1, 那么在 \(B\) 和 \(A\) 中其第 \(i\) 和 \(i + 1\) 位分别为 0, 1. 所以这就等价于在 \(B - A\) 中 \(i\) 和 \(i + 1\) 位都是 0 的情况.
- 如果 \(x, y\) 在第 \(i\) 位上有一个 1, 那么在 \(B\) 中其第 \(i\) 和 \(i + 1\) 位分别为 0, 1, 在 \(A\) 中第 \(i\) 位是 1. 所以在 \(B - A\) 中第 \(i\) 和 \(i + 1\) 位分别为 1, 0.
- 如果 \(x, y\) 在第 \(i\) 位上都是 0, 那么在 \(A\) 中第 \(i\) 位是 0, 在 \(B - A\) 中第 \(i\) 和 \(i + 1\) 位就分别是 0, 1.
对于 \(x, y\) 的偶数位我们分析完成, 那么奇数位的分析只需要依靠 \(A - x' - y'\) 即可, 其中 \(x', y'\) 均为目前分析出来的数.
道理是相同的, 就不过多赘述了.
最后放一下代码
#include "iostream"
using namespace std;
#define int long long
void solve() {
int T = 1, x = 0, y = 0;
for (int i = 0; i < 30; i += 2) x += 1 << i;
cin >> T;
while (T--) {
int a, b, m, p = 0, q = 0;
cout << x << endl, cin >> b;
cout << y << endl, cin >> a;
cout << '!' << endl, cin >> m;
b -= a;
for (int i = 0; i < 30; i += 2) {
if (b >> i & 1) p += 1 << i;
else if (!(b >> (i + 1) & 1)) p += 1 << i, q += 1 << i;
}
a -= p + q;
for (int i = 1; i < 30; i += 2) {
if (a >> i & 1) p += 1 << i;
else if (a >> (i + 1) & 1) p += 1 << i, q += 1 << i;
}
cout << (m | p) + (m | q) << endl;
}
}
signed main() {
solve();
return 0;
}

浙公网安备 33010602011771号