题面
题意
- 交互题,输入一个n,会有一个序列(序列中的数就是1…n乱序排列),然后你可以询问最多100次,来找出序列中一个局部最小值(就是这个数小于它左右两边的数)
- 模拟样例:输入一个n =5, 然后程序问你 下标为3 的位置数的值,然后你输入1 ,然后程序问你下标为2的位置的值,然后你输入2 ,然后程序问你下标为1的位置的值,你输入3 ,然后程序问你下标为4的位置的值,你输入4,然后程序问你下标为5的位置的值,你输入5,然后你输入5,最后程序返回一个局部最小值1的下标3
题解
- 之前也没怎么做过交互题,然后昨天晚上就没做出来,百度说交互题一般经验都是二分/三分找区间值,题中n是1e5,二分时间复杂度O(logn),找100次可以实现
- 题中要求找一个局部最小值,也就是找一个‘ V ’ 形的区间,那么中间值就是局部最小值,我们可以二分中间值mid,然后再询问一个mid+1 的值, 如果a[mid]>a[mid+1],说明这一部分单调递减,那么继续向右二分看是否还是单调递减,(因为右边边界是正无穷,所以一定存在递增区间) 以此来缩小区间,如果继续找是递增那么这个局部最小值就在这个区间,继续缩小区间,直到找到
- a[mid]<a[mid+1] 说明这个区间就是单调递增,因为左边界是正无穷,所以肯定有解,继续向左缩小区间,其余同上
代码
#include<bits/stdc++.h>
using namespace std;
int main() {
int n, x, y;
scanf("%d", &n);
int l = 1, r = n;
while (l < r) {
int mid = (l + r) >> 1;
printf("? %d\n", mid);
fflush(stdout);
scanf("%d", &x);
printf("? %d\n", mid + 1);
fflush(stdout);
scanf("%d", &y);
//说明这个区间单调递减,那么就要向右找一个单调递增的区间
if (x > y) l = mid + 1;
//这个区间单调递增,就要向左找一个单调递减的区间
else r = mid;
}
printf("! %d", l);
fflush(stdout);
return 0;
}