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;
}
posted @ 2025-03-11 15:54  Steven1013  阅读(20)  评论(0)    收藏  举报