CF1364 E - X-OR // Codeforces Round #649 (Div. 2)E - X-OR 交互思维题

比较显然的思路是找0的位置。

通过0来确定每个位置数的值。

如何找0的位置呢?

假如有a,b,c三个数

如果 ( a | b ) > ( b | c )  则a一定不是0,显然前者b通过或a  结果变大了

如果 ( a | b ) < ( b | c )  则c一定不是0,

如果  ( a | b ) == ( b | c )  则b一定不是0,因为如果b是0,则有a==c,显然不可能。

通过上述我们就可以枚举,然后每次更新a,b 为0的候选位置。

需要的次数为 n+x

然后再枚举i,询问(a | i)  (b | i)的关系,判断a,b谁是0.

需要的次数为y

最后枚举i,得出结果

需要的次数为n

总次数为2*n+x+y

先分析x,肯定是( a | b ) == ( b | c )  时,我们需要额外询问一次 a | c 。

两个数或等于另外两个数 ,总共就11位数,数组随机的情况下,次数很少。

y同理。

通过随机数据可知 x+y约等于11  所以算法可行。。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double PI= acos(-1.0);
const int M = 3000+7;
/*
int head[M],cnt;
void init(){cnt=0,memset(head,0,sizeof(head));}
struct EDGE{int to,nxt,w;}ee[M*2];
void add(int x,int y,int w){ee[++cnt].nxt=head[x],ee[cnt].w=w,ee[cnt].to=y,head[x]=cnt;}
*/
int p[M];
int mp[M][M];
int ask(int x,int y)
{
	if(x<y)swap(x,y);
	if(mp[x][y])return mp[x][y];
	cout<<"? "<<x<<" "<<y<<endl;
	int tp;
	cin>>tp;
	mp[x][y]=tp;
	return tp;
}
int main()
{
	ios::sync_with_stdio(false);
  	cin.tie(0);
  	int n;
  	cin>>n;
  	int a=1,b=2,tp=0;
  	tp=ask(a,b);
  	for(int i=3;i<=n;i++)
  	{
  		int nw=ask(b,i);
  		if(tp>nw)//a一定不是0
		{
			a=i;
			tp=nw;	
		}
		else if(tp<nw);//c一定不是0 
		else //b一定不是0 
		{
			tp=ask(a,i);
			b=i;
		}
	}
//	cout<<a<<" -- "<<b<< "  -- "<<tp<<endl;
	int id=0;
	//while(1)int i=uniform_int_distribution<int>(1,n)(rng);
	for(int i=1;i<=n;i++)
	{
		if(i==a||i==b)continue;
		int x=ask(a,i),y=ask(b,i);
		if(x==y)continue;
		if(x<y)id=a;
		else id=b;
		break;
	}
//	cout<<id<<endl;
	for(int i=1;i<=n;i++)
	{
		if(i==id)continue;
		p[i]=ask(i,id);
	}
	cout<<"!";
	for(int i=1;i<=n;i++)
		cout<<" "<<p[i];
	cout<<endl;
	return 0;
}

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值