[CF1479A/CF1480C] Searching Local Minimum

[CF1479A] Searching Local Minimum - 二分

Description

藏一个排列,(n le 10^5),最多 100 次询问,找到任意一个局部最小值 (a_i<a_{i+1},a_i<a_{i-1})

Solution

先把一些容易判的判掉,比如 (nle 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("...");
}
原文地址:https://www.cnblogs.com/mollnn/p/14387524.html