【CF1451E2】Bitwise Queries (Hard Version)

题目

题目链接: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\)的整数次幂。

思路

首先肯定把 \(2\sim n\) 元素与 \(1\) 号元素异或一遍,然后考虑在 \(2\) 次询问内得到 \(1\) 号元素。
分两类情况讨论:

  1. 存在两个元素相等,那么我们直接把这两个元素找出来(要么两个异或 \(1\) 号元素相等,要么存在一个元素疑异或 \(1\) 号元素为 \(0\))。把他们 OR 一下就可以得到了。
  2. 不存在两个元素相等,那么必然是 \(0\sim 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\n",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\n",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\n",i); fflush(stdout);
				scanf("%d",&x);
			}
			if (a[i]==(n>>1))
			{
				printf("OR 1 %d\n",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;
}
posted @ 2021-03-05 13:11  stoorz  阅读(57)  评论(0编辑  收藏  举报