题目
给定一个长度为 \(n\ (1 \leq n \leq 10^5)\) 的排列 \(a_{1 \sim n }\) ,每次可以提问一个下标 \(i\) ,交互器会返回对应的 \(a_i\) 的值。
请在 \(100\) 次询问内找出一个任意一个下标 \(i\ (1\leq i \leq n)\) 满足 \(a_i < \min\{a_{i-1},a_{i+1}\}\) ,规定 \(a_0=a_{n+1}=+\infin\) 。
思路
一个结论是:若排列在\([l,l+1]\)内递减,在\([r-1,r]\)内递增,则\([l,r]\)内一定有至少一个解,自己画画图即可理解.
根据题意,序列在\([0,1]\)递减,\([n,n+1]\)递增,所以必定有解.
考虑二分答案,枚举一个\(mid\),若\([mid,mid+1]\)减,取右区间,否则,取左区间.
代码
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int read() {
int re = 0;
char c = getchar();
bool negt = false;
while(c < '0' || c > '9')
negt |= (c == '-') , c = getchar();
while(c >= '0' && c <= '9')
re = (re << 1) + (re << 3) + c - '0' , c = getchar();
return negt ? -re : re;
}
template <char l , char r>
char readc() {
char c = getchar();
while(c < l || c > r)c = getchar();
return c;
}
const int N = 1e5 + 10;
int n;
int a[N];
int ask(int pos) {
if(a[pos] == -1) {
cout << "? " << pos << endl;
cin >> a[pos];
}
return a[pos];
}
void solve() {
memset(a , -1 , sizeof(a));
n = read();
int l = 1 , r = n;
a[0] = a[n + 1] = n + 1;
while(l <= r) {
int mid = (l + r) / 2;
int s1 = ask(mid);
int s2 = ask(mid + 1);
if(s1 > s2) l = mid + 1;
else r = mid - 1;
}
cout << "! " << l;
}
int main() {
solve();
return 0;
}