题目
题目链接:https://codeforces.com/problemset/problem/1451/E2
Ridbit 有一个隐藏的长度为 (n) 的整数数组 (a),想让 Ashish 去猜,注意 (n) 是 (2) 的整数次幂。Ridbit 允许 Ashish 提出三种不同类型的查询。它们分别是:
AND (i) (j): 求元素 (a_i) 和 (a_j) 每一位的 (and) ((1≤i),(j≤n),(i≠j))
OR (i) (j): 求元素 (a_i) 和 (a_j) 每一位的 (or) ((1≤i),(j≤n),(i≠j))
XOR (i) (j): 求元素 (a_i) 和 (a_j) 每一位的 (xor) ((1≤i),(j≤n),(i≠j))
有限制:(1) Ashish 最多可以询问 (n + 1) 次。(2) (a) 数组满足 (0 le a_i le n - 1)。
(n)在(4 leq n leq 2^{16}),也就是数组的长度。同时保证(n)是(2)的整数次幂。
思路
首先肯定把 (2sim n) 元素与 (1) 号元素异或一遍,然后考虑在 (2) 次询问内得到 (1) 号元素。
分两类情况讨论:
- 存在两个元素相等,那么我们直接把这两个元素找出来(要么两个异或 (1) 号元素相等,要么存在一个元素疑异或 (1) 号元素为 (0))。把他们
OR
一下就可以得到了。 - 不存在两个元素相等,那么必然是 (0sim n-1) 每一个数字恰好出现一次。那么找到异或 (1) 号元素为 (1) 的元素,询问它和 (1) 号元素的
OR
,就可以得到 (1) 号元素的前 (log n-1) 位,再找到异或一号元素等于 (frac{n}{2}) 的元素,询问它与 (1) 号元素的OR
,就可以得到 (1) 号元素的后 (log n-1) 位。综合一下就可以得到 (1) 号元素了。
这样显然操作次数最多为 (n+1),时间复杂度 (O(n))。
代码
#include <bits/stdc++.h>
using namespace std;
const int N=(1<<16)+10;
int n,flag,a[N],b[N],pos[N];
int main()
{
scanf("%d",&n);
pos[0]=1;
for (int i=2;i<=n;i++)
{
printf("XOR 1 %d
",i); fflush(stdout);
scanf("%d",&a[i]);
if (pos[a[i]]) flag=pos[a[i]];
pos[a[i]]=i;
}
if (flag)
{
printf("OR %d %d
",flag,pos[a[flag]]); fflush(stdout);
scanf("%d",&b[flag]);
b[pos[a[flag]]]=b[flag];
b[1]=a[flag]^b[flag];
}
else
{
int x=0,y=0;
for (int i=2;i<=n;i++)
{
if (a[i]==1)
{
printf("OR 1 %d
",i); fflush(stdout);
scanf("%d",&x);
}
if (a[i]==(n>>1))
{
printf("OR 1 %d
",i); fflush(stdout);
scanf("%d",&y);
}
}
b[1]=((x>>1)<<1)|(y&1);
}
printf("! %d",b[1]);
for (int i=2;i<=n;i++)
printf(" %d",b[1]^a[i]);
fflush(stdout);
return 0;
}