版权声明:欢迎大家指正错误,有不同观点的欢迎评论,共同进步 https://blog.csdn.net/Sirius_han/article/details/81744434
题意:有n个数围成一圈,相邻的两个数之间差为1,由1~n标号,n是偶数;问是否存在这样的一对儿数(a[i]a[i+n/2]),使得a[i]=a[i+n/2];如果存在,输出下标i,反之输出-1;题目只给出n的值,可以以 "? x" 的形式询问下标是x的数值是几;最多问60次就要给出答案;由于n的范围是[2, 1e5],显然不能一个个的问;问60次相当于是log的复杂度,首先想到的就是二分,但是二分谁?怎么分?这是一个问题;
题目指出,相邻两个数差为1;我们就应该从这里找突破口;而a[i], a[i+n/2]是相对的,那么我们可以把n个数分成两排,1~n/2,一排,n/2+1~n,一排;就是找上下相对的值相同的那对儿数;
首先,因为相邻差1,所以如果i为奇数,那么i+1, i-1为偶数,只有当n%4==0的时候才会出现偶对偶, 奇对奇的情况;所以其他情况都输出"! -1";
再看n%4==0的情况,下图id表示下标,a 表示值,d表示上下对应位置的差值:
可以看到,d=0时就是我们要找的;
而d=0必然存在与大于零,与小于零的中间,所以二分法找;
#include <bits/stdc++.h>
using namespace std;
int n;
int cal(int x){
x;
cout << "? " << x << endl;
int a, b;
cin >> a;
cout << "? " << x+n/2 << endl;
cin >> b;
if(a==b){
cout << "! " << x << endl;
exit(0);
}
return a<b;
}
int main(){
cin >> n;
if(n%4){
cout << "! " << -1 << endl;
return 0;
}
int l=1, r=n/2+1, type=cal(1);//type 表示第一对儿的差值是正还是负
while(l<r){
int mid=(l+r)>>1;
int t=cal(mid);//如果t和type符号不同,那么d=0的位置一定在两点中间;
if(t==type) l=mid+1;
else r=mid;
}
cout << "! " << -1 << endl;
return 0;
}