中位数只关心数的大小关系,而不是确切的值,所以我们可以从 1 ~ (2 * n - 1)
二分答案出一个数 X
,将底端 < X
的数赋为 0
,> X
的数赋为 1
。
一个格子的值一定等于 这个格子下面三个格子的数中至少有两个数相同的数。
第 n
列的最顶部格子的值一定和离这个格子最近的两个有相同数的格子的值相同。
那么判断 mid
是否可行,我们只要从最低端第 n
列开始 同时向左向右不停查找 有相同的值的两个相邻格子,一旦找到有这样的两个格子就返回这两个格子的值。注意如果没有这样的两个格子,显然就返回第一个数值即可。
如果返回值为 1
则表示这个二分出来的值大于了最后答案,如果为 0
反之,显然我们就是要求最小的返回值为 1
的 mid
。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int nn, n;
int a[N << 1];
int small(int x, int y, int k) {
return (a[x] <= k && a[y] <= k);
}
int big(int x, int y, int k) {
return (a[x] > k && a[y] > k);
}
bool check(int k) {
if (small(n, n - 1, k) || small(n, n + 1, k)) return 0;
if (big(n, n - 1, k) || big(n, n + 1, k)) return 1;
for (int i = 1; i < n - 1; i ++) {
if (small(n - i, n - i - 1, k) || small(n + i, n + i + 1, k)) return 0;
if (big(n - i, n - i - 1, k) || big(n + i, n + i + 1, k)) return 1;
}
return big(1, 1, k);
}
int main() {
scanf("%d", &n);
nn = 2 * n - 1;
for (int i = 1; i <= nn; i ++) scanf("%d", &a[i]);
int l = 1, r = nn, pos;
while (l < r) {
int mid = (l + r) >> 1;
if (check(mid)) l = mid + 1;
else r = mid;
}
printf("%d\n", r);
return 0;
}