我们在区间里二分,想一想局部最小值的定义 a i − 1 > a i & & a i < a i + 1 a_{i-1}>a_i\&\&a_i<a_{i+1} ai−1>ai&&ai<ai+1
初始 l = 1 , r = n l=1,r=n l=1,r=n
这就有一个很好玩的性质, a l − 1 > a l & & a r < a r + 1 a_{l-1}>a_l\&\&a_{r}<a_{r+1} al−1>al&&ar<ar+1
如果我们能在二分的过程中维护住这个性质,最后二分到 l = = r l==r l==r时
这个点就同时满足比两边小
那我们取区间中点 m i d mid mid
若 a [ m i d ] < a [ m i d + 1 ] a[mid]<a[mid+1] a[mid]<a[mid+1]
那么区间 [ l , m i d ] [l,mid] [l,mid]仍然满足上述性质
若 a [ m i d ] > a [ m i d + 1 ] a[mid]>a[mid+1] a[mid]>a[mid+1]
那么区间 [ m i d + 1 , r ] [mid+1,r] [mid+1,r]仍然满足上述性质
综上所述,我们总能维护一个这样的区间
所以可以在 l o g 2 ( n ) log2(n) log2(n)次后得到解
#include <bits/stdc++.h>
using namespace std;
int n,a[100009];
void get(int x)
{
if( x>n||x<1||a[x] ) return;
cout << "? " << x << endl;
fflush(stdout);
cin >> a[x];
}
int main()
{
cin >> n;
a[0] = a[n+1] = 1e9;
get(1); get(n);
int l = 1,r = n;
while( r>l )
{
int mid = l+r>>1;
get(mid); get(mid+1);
if( a[mid]>a[mid+1] ) l = mid+1;//
else r = mid;
}
printf("! %d\n",r);
}