Codeforces Round #503 (by SIS, Div. 1) B. The hat (交互式题目,二分)

版权声明:欢迎大家指正错误,有不同观点的欢迎评论,共同进步 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;
}

猜你喜欢

转载自blog.csdn.net/Sirius_han/article/details/81744434