cf1415 E1. Bitwise Queries (Easy Version)
题意:
交互题
猜一个数组,长度已知为 n
每次可询问 \(i,j\) 并选择 and/or/xor 中的一种运算,回答 \(a_i\) 运算 \(a_j\) 的值
n 是 2 的倍数,\(0\le a_i < n-1\)
询问次数:Easy Version \(n+2\),Hard Version \(n+1\)
思路:
key:\(a+b=a\oplus b + 2(a\&b)\) (到底怎么发现的啊)
异或老好用了,知道了一个数的值,其他数都跟它异或一下就能得到所有数。
那怎样算出一个数呢?
easy ver
询问 \(a_1 \& a_2,a_2\&a_3,a_1\&a_3\),然后问 \(a_1\oplus a_2,a_1\oplus a_3\),那么 \(a_2\oplus a_3=(a_1\oplus a_2)\oplus (a_1\oplus a_3)\)
代进那个神奇等式,就知道了 \(a_1+a_2,a_2+a_3,a_1+a_3\),解方程算出 \(a_1,a_2,a_3\)。也就是说我们用 5 个询问得到了三个数。接下来问 n-3 个异或即可。
hard ver
先把所有数和 1 异或。这样就花掉 n-1 次询问了,接下来要用两次询问求出 \(a_1\)
如果某个数 x 异或 1 得 0,说明 \(x=a_1\)。直接询问 \(a_1=a_1 | x\)
如果某俩数 \(x\oplus a_1=y\oplus a_1\),说明 \(x=y\)。直接询问 \(x=x|y\)
否则,说明数组中的数两两不同,即 \([0,n-1]\) 中的每个数出现一次。那么肯定有一个与 \(a_1\) “二进制互补” 的数 x,\(a_1\oplus x=(1111)_2=n-1\),
显然 \(a_1\& x=0\),我们再随便另取一个 y,询问 \(x\&y\)。这样又可以解方程得到三个数
//easy version
const signed N = (1<<17);
const char op[3][5] = {"AND","OR","XOR"};
int ask(int i, int j, int ty) {
cout << op[ty] << ' ' << i << ' ' << j << endl;
int res; cin >> res; return res;
}
int n, a[N];
signed main() {
cin >> n;
for(int i = 2; i <= n; i++) a[i] = ask(1,i,2);
int a12 = ask(1,2,0), a23 = ask(2,3,0), a13 = ask(1,3,0);
a12 = a12*2+a[2], a13 = a13*2+a[3], a23 = a23*2+(a[2]^a[3]);
a[1] = (a12+a13+a23)/2-a23;
cout << "! " << a[1];
for(int i = 2; i <= n; i++) cout << ' ' << (a[i]^a[1]);
cout << endl;
}

浙公网安备 33010602011771号