zoukankan      html  css  js  c++  java
  • CF1364E X-OR

    蒟蒻的第一道正式交互题QWQ。

    首先我们要明确一点:如果知道了排列中 (0) 的位置,所有其他位置均可以通过一次询问求出。所以我们的思路是首先找到 (0) 的位置。

    考虑一个暴力的判断一个位置 (x) 是否是 (0) 的方法:

    1. 随机出 30个值域在([0,n-1])范围内的数,记作 (a) 序列
    2. (res=2047),然后依次 (res&=Query(a[i],x))
    3. 若任何时刻 (res=0),则立刻判断 (x) 位置为 (0),若最后 (res) 都不为 (0),则可以大致判断 (x) 位置不为 (0)

    (其中 (Query) 为对交互库的询问,上面算法在很大的概率上是正确的)

    但显然我们不能对每个位置依次判断其是否为 (0)

    但我们可以很快的排除不是 (0) 的位置。

    给你三个位置 (a,b,c)(Query(a,b)) 的答案 (now)

    1. (Query(a,c)<now),则 (b) 位置处不为 (0)
    2. (Query(a,c)>now),则 (c) 位置处不为 (0)
    3. (Query(a,c)=now),则 (a) 位置处不为 (0)

    其中对1.2.的解释是 (0) 位置和任何位置的 (Query) 都为 (0),是不可能大于一个其他的 (Query) 的,对3.的解释是因为你要猜的数列是一个排列,所以 (b eq c),所以显然 (a) 也不能为 (0)

    上述流程可以对任意三个位置通过一次询问排除一个位置是 (0) 的可能性,这也就告诉我们,在进行 (n-2) 次询问后,只有 (2) 个位置可能为 (0),这时我们在使用最上面的暴力判断方法,就可以在很少次数内找到 (0) 的位置,这道题就做完了。

    代码:

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<ctime>
    
    using namespace std;
    
    const int N=3000;
    int n,p[N],ans[N];
    
    int Get(int x,int y)
    {
    	printf("? %d %d
    ",x,y);
    	fflush(stdout);
    	int k;
    	scanf("%d",&k);
    	return k;
    //	return p[x]|p[y];
    }
    
    void init()
    {
    	scanf("%d",&n);
    }
    
    bool check(int x)
    {
    	int A=2047;
    	for (int _=1;_<=30;_++)
    	{
    		int tmp=rand()%n+1;
    		while(tmp==x) tmp=rand()%n+1;
    		A&=Get(x,tmp);
    		if(A==0) return 1;
    	}
    	return 0;
    }
    
    void prework()
    {
    	n=rand()%10+1;
    	while(n<3) n=rand()%10+1;
    	for (int i=1;i<=n;i++)
    		p[i]=i-1;
    	random_shuffle(p+1,p+1+n);
    	printf("%d
    ",n);
    	for (int i=1;i<=n;i++)
    		printf("%d ",p[i]);puts("");
    }
    
    void work()
    {
    	int A=1,B=2,now=Get(A,B);
    	for (int i=3;i<=n;i++)
    	{
    		int C=Get(A,i);
    		if(C<now) B=i,now=C;
    		else if(C==now) A=i,now=Get(A,B);
    	}
    	int pos=check(A)?A:B;
    	for (int i=1;i<=n;i++)
    		if(i!=pos)
    			ans[i]=Get(pos,i);
    	printf("! ");
    	for (int i=1;i<n;i++)
    		printf("%d ",ans[i]);
    	printf("%d
    ",ans[n]);
    	fflush(stdout);
    }
    
    int main()
    {
    	srand(time(0));
    //	prework();
    	init();
    	work();
    	return 0;
    }
    
    由于博主比较菜,所以有很多东西待学习,大部分文章会持续更新,另外如果有出错或者不周之处,欢迎大家在评论中指出!
  • 相关阅读:
    623. Add One Row to Tree 将一行添加到树中
    771. Jewels and Stones 珠宝和石头
    216. Combination Sum III 组合总数三
    384. Shuffle an Array 随机播放一个数组
    382. Linked List Random Node 链接列表随机节点
    向github项目push代码后,Jenkins实现其自动构建
    centos下安装Jenkins
    python提取批量文件内的指定内容
    批处理实现:批量为文件添加注释
    python抓取每期双色球中奖号码,用于分析
  • 原文地址:https://www.cnblogs.com/With-penguin/p/13193502.html
Copyright © 2011-2022 走看看