[CF1479A] Searching Local Minimum - 二分
Description
藏一个排列,\(n \le 10^5\),最多 100 次询问,找到任意一个局部最小值 \(a_i<a_{i+1},a_i<a_{i-1}\)
Solution
先把一些容易判的判掉,比如 \(n\le 100\),\(a_1,a_n\) 之类
类似二分,维护两个端点,每次取中间,看中间这个位置的相邻三个元素是什么大小关系
如果中间最小,运气太好,那么已经找到答案,直接结束
如果中间最大,随便往哪边走
如果是单调的,那么往有减小趋势的那边走
(并不会证明)
#include <bits/stdc++.h>
using namespace std;
int ask(int i)
{
cout << "? " << i << endl;
cout.flush();
int x;
cin >> x;
return x;
}
void finish(int x)
{
cout << "! " << x << endl;
cout.flush();
exit(0);
}
const int N = 100005;
int n, a[N];
void test(int x)
{
if (x == 1 || x == n)
return;
int mid = x;
int xl = ask(mid - 1), xm = ask(mid), xr = ask(mid + 1);
if (xl > xm && xm < xr)
finish(mid);
}
signed main()
{
cin >> n;
if (n == 1)
{
finish(1);
}
if (n <= 100)
{
for (int i = 1; i <= n; i++)
a[i] = ask(i);
finish(min_element(a + 1, a + n + 1) - a);
}
a[1] = ask(1);
a[2] = ask(2);
a[n - 1] = ask(n - 1);
a[n] = ask(n);
if (a[1] < a[2])
finish(1);
if (a[n - 1] > a[n])
finish(n);
int l = 1, r = n;
while (r - l > 3)
{
int mid = (l + r) / 2;
int xl = ask(mid - 1), xm = ask(mid), xr = ask(mid + 1);
if (xl > xm && xm < xr)
finish(mid);
if (xl < xm && xm < xr)
r = mid;
else if (xl > xm && xm > xr)
l = mid;
else
r = mid;
}
for (int i = l; i <= r; i++)
test(i);
throw("...");
}