CodeForces - 1451E2-Bitwise Queries(Hard Version) ( 交互 + 位运算 )

这篇博客探讨了一种在最多n+1次询问下确定长度为n的数组(n为2的幂次)内容的方法。文章详细介绍了如何通过三种类型的询问(AND、OR、XOR)来区分数组内是否存在相同值的情况,并给出相应的解决策略。在数组元素范围为[0,n-1]的情况下,通过初始化查询和特定条件判断,最终确定整个数组的值。
摘要由CSDN通过智能技术生成
题目链接:点击进入
题目

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

题意

长度为n的数组(n 是 2 的幂次),数组内每个数的范围在 [ 0 , n - 1 ] ,求在最多n+1次询问下确定整个数组
询问有三种类型:
1、询问 a [ i ] and a [ j ] 的值
2、询问 a [ i ] or a [ j ] 的值
3、询问 a [ i ] xor a [ j ] 的值

思路

数组有两种情况
1、数组内出现相同值
2、数组内没有相同的值( 即 [ 0 - n - 1 ] 各自出现一次 )
首先这两种情况我们都初始先花费 n - 1 次查询,得到 a [ 1 ] 与 a [ 2 ] … a [ n ] 的 xor 值 x [ i ]
然后
对于情况 1 ,若两个值 a [ i ] 跟 a [ j ] 相同,则他们与 a [ 1 ] 的 xor 值 x [ i ] 与 x [ j ] 相同,此时询问 a [ i ] 与 a [ j ] 的 and 值,得到的就是 a[ i ] 本身,又因为 a [ 1 ] xor a [ i ] = x [ i ] ,则 a [ 1 ] = a [ i ] ^ x [ i ] ,确定了 a [ 1 ] ,有已知 a [ 1 ] 与剩余的值的 xor 值,因此确定了整个数组,共 n 次查询;同时,若两个相等的数中有一个 a [ 1 ] ,则可以通过 x [ i ] 是否等于 0 来判断
对于情况 2 ,因为 0 - n - 1 的数都有,所以必定会有 a [ i ] xor a [ j ] = n - 1 (即 a [ i ] and a [ j ] = 0 ),根据这个性质,a [ 1 ] = a [ 1 ] and a [ i ] + a [ 1 ] and a [ j ] ,通过两次询问得到 a [ 1 ] ,共 n + 1 次询问
所以最多 n + 1 次询问即可确定整个数组。

代码
//#pragma GCC optimize(3)//O3
//#pragma GCC optimize(2)//O2
#include<iostream>
#include<string>
#include<map>
#include<set>
//#include<unordered_map>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#include<iomanip>
#include<cmath>
#include<fstream>
#define X first
#define Y second
#define best 131 
#define INF 0x3f3f3f3f3f3f3f3f
#define pii pair<int,int>
#define lowbit(x) x & -x
#define inf 0x3f3f3f3f
//#define int long long
//#define double long double
//#define max(a,b) a>b?a:b
//#define min(a,b) a<b?a:b
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double pai=acos(-1.0);
const int maxn=1e6+10;
const int mod=1e9+7;
const double eps=1e-9;
const int N=1e6+10;
int t,n,m,k,d,x[maxn],a[maxn];
map<int,int>mp;
int ask(int i,int j,int f)
{
	if(f==1) 
	{
		cout<<"AND "<<i<<" "<<j<<endl;
		cout.flush();
	}
	else if(f==2)
	{
		cout<<"OR "<<i<<" "<<j<<endl;
		cout.flush();
	}
	else if(f==3)
	{
		cout<<"XOR "<<i<<" "<<j<<endl;
		cout.flush(); 
	}
	int x;
	cin>>x;
	return x;
}
int main()
{	
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);	
	cin>>n;
	for(int i=2;i<=n;i++)
		x[i]=ask(1,i,3);
	int flag=-1;
	for(int i=2;i<=n;i++)
	{
		if(x[i]==0)
        {
            flag=ask(1,i,1);
            break;
        }
        if(mp.count(x[i]))
        {
            int tmp=mp[x[i]];
            flag=ask(tmp,i,1);
            flag=flag^x[i];
            break;
        }
		mp[x[i]]=i;
	}
	if(flag==-1)
	{
		mp.clear();
		for(int i=2;i<=n;i++)
        {
            if(mp.count((n-1)^x[i]))
            {
                int num1=mp[(n-1)^x[i]];
                int num2=i;flag=0;
                flag+=ask(1,num1,1);
                flag+=ask(1,num2,1);
                break;
            }
            mp[x[i]] = i;
        }
	}
	a[1]=flag;
	for(int i=2;i<=n;i++)
		a[i]=a[1]^x[i];
	cout<<"!";
	cout.flush();
	for(int i=1;i<=n;i++)
		cout<<" "<<a[i],cout.flush();
	cout<<endl;
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值