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;
}

 

posted @ 2020-02-04 15:28  DD_XYX  阅读(43)  评论(0)    收藏  举报