CF1019B The hat (二分)
题面

题解
如果位置为i的人与对面的差是x,i+1位置由于只能+1或-1,所以i+1位置与对面的差就是x、x+2或x-2,可以发现,奇偶性不变。
所以只要判断出是奇差,就可以直接输出“! -1”,如果是偶差,就一定有解。
下面是个圆环,从1~n/2+1开始,顺时针转,记L=1,R=n/2+1。

把两个点转半圈的函数记录下来:(谁是L谁是R已经不重要了)

会发现两者一定有一个交点,而且由于差是偶数,中间的交点一定是整点!
下面看怎么求随便一个交点:
如果我们发现一对中间点,那么有两种情况。
第一种,a[L'] - a[R']与a[L] - a[R]同号:

第二种,异号:

可以发现,第一种情况,紫线右边一定有解,可以跑到右边解去,第二种情况,紫线左边一定有解,可以放弃右边解左边
我们何不就问中点,这样就可以二分了。
CODE
#include<cstdio>
#include<cstring>
#include<vector>
#include<stack>
#include<queue>
#include<algorithm>
#include<map>
#include<cmath>
#include<iostream>
#define MAXN 100005
#define LL long long
using namespace std;
int read() {
int f = 1,x = 0;char s = getchar();
while(s < '0' || s > '9') {if(s == '-')f = -1;s = getchar();}
while(s >= '0' && s <= '9') {x = x * 10 + s - '0';s = getchar();}
return x * f;
}
int n,m,i,j,k,s,o,N;
int askpair(int x) {
int y = x + (N/2),a,b;
cout<<"? "<<x<<endl;
cin>>a;
cout<<"? "<<y<<endl;
cin>>b;
return a - b;
}
int main() {
N = n = read();
if((n/2) & 1) {
cout<<"! -1"<<endl;
return 0;
}
int l = 1,r = n/2 + 1;
int asp = askpair(1);
if(asp == 0) {
cout<<"! 1"<<endl;
return 0;
}
while(l < r) {
int mid = l + r >> 1;
int asn = askpair(mid);
if(asn == 0) {
cout<<"! "<<mid<<endl;
return 0;
}
if(asn * asp > 0) {
l = mid + 1;
}
else r = mid;
}
cout<<"! "<<l<<endl;
return 0;
}

浙公网安备 33010602011771号