Codeforces Round #503 (by SIS, Div. 1)D. the hat

原题链接:B. The hat

题意:有n(偶数)个人围成一个圈,每个人身上有一个数字,保证相邻两个人的数字差为1,

现在要把第i个人和第i+n/2个人面对面站着,例如现在有8个人,站好后如下:

1 2 1 2

3 4 3 2

第1个人和第5个人面对面,第2个人和第6个人面对面,以此类推。。。

现在的问题是你可以询问q(q<=60)次,在n(2<=n<=100000)个人中

找出一对面对面站着且数字相同的人,输出这两个人任意一个人的位置,没找到输出-1;

首先当n%4!=0的时候我们直接输出-1即可,为什么可以这样?

我们可以先看一组数据:

1 2 3

2 1 2

第一个人为奇数,那么因为保证相邻两个人的数字差为1,所以第二个人肯定为偶数。。。第一排最后一个为奇数

下面一排的第一个人跟第一排的最后一个人数字差为1,所以他肯定为偶数,于是上面一排跟下面一排奇偶性刚好错开

所以上面的数不可能等于下面的数,证完了,是不是很简单?

OK,接下来我们考虑一般情况,一共最多有50000对数,我们只可以询问

最多60次,如果从前往后直接询问肯定不行,有经验的选手容易想到二分查找,

没错,这道题还真就是二分查找,怎么查找呢,我们先看一组数据:

7 6 5 4 5 6 5 4 3 2

1 2 3 4 3 2 3 4 5 6

设上面一排为A,第i个数为Ai,下面一排为B,第i个数为Bi

A1>B1,A只有往后减少,B往后增加中间才能出现相等的情况,并且由于最后An要和B1要相差1,Bn和A1也要相差1

所以肯定是有解的。先查第一对,A1=7,B1=1,得出上下排大小关系然后在第二对和最后一对中间进行二分查找,具体实现见代码:

#include <bits/stdc++.h>
using namespace std;
int n,x,y,a,b;
int main(){
    cin>>n;
    if(n%4!=0){
        printf("! -1\n");
        return 0;
    }
    printf("? 1\n");
    cin>>x;
    printf("? %d\n",1+n/2);
    cin>>y;
    if(x==y){
        printf("! %d\n",x);
        return 0;
    }
    int l=2,r=n/2;
    while(l<=r){
        int m=(l+r)/2;
        printf("? %d\n",m);
        cin>>a;
        printf("? %d\n",m+n/2);
        cin>>b;
        if(a==b){
            printf("! %d\n",m);
            return 0;
        }
        else if(x>y&&a>b||x<y&&a<b)l=m+1;
        else r=m;
    }
}

 

posted @ 2018-08-14 19:14  Venux  阅读(188)  评论(0编辑  收藏  举报