題面
題解
如果位置爲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;
}