Codeforces Round #503 (by SIS, Div. 1)D. 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; } }