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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章