[二分] [思维] AT_agc006_d [AGC006D] Median Pyramid Hard
posted on 2025-02-25 13:26:26 | under | source
题意:有一个高 \(n\) 的金字塔型数格,底层 \(2n-1\) 个格子,每上一层丢掉两侧格子。给出底层格子的数 \(p\) 为排列,定义上一层的数 \(b_i\) 为该层 \(a_{i-1},a_i,a_{i+1}\) 的中位数,求顶端的数。\(n\le 10^5\)。
显然二分,转化为 \(01\) 序列,操作也就是取众数。
手玩一下,发现对于相邻两个相同的数,会不断向上蔓延,大胆猜测离中点最近的数对即为答案。
不难证明:因为它离中点最近,所以它到中点的 \(p\) 一定是 \(01\) 交替的,所以每一轮它不仅向上蔓延,还会向中点方向蔓延,所以它会最先使得中点出现相同的两个数,所以塔尖的数就是它。
容易发现不可能存在两个不同(是指值不同)的相同数对,所以没有问题。不过可能不存在相同数对,特判即可。
\(O(n\log n)\)。
代码
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5, inf = 1e9;
int n, nn, a[N], b[N];
inline int myz(int x) {return x < 0 ? -x : x;}
inline bool solve(int k){
for(int i = 1; i <= nn; ++i) b[i] = (a[i] <= k);
int mi = inf, mi1 = inf;
for(int i = 1; i < nn; ++i){
if(!b[i] && !b[i + 1]) mi = min(mi, myz(n - i)), mi = min(mi, myz(n - i - 1));
if(b[i] && b[i + 1]) mi1 = min(mi1, myz(n - i)), mi1 = min(mi1, myz(n - i - 1));
}
if(mi == inf && mi1 == inf) return b[1];
return mi1 < mi;
}
signed main(){
cin >> n, nn = n * 2 - 1;
for(int i = 1; i <= nn; ++i) scanf("%d", &a[i]);
int L = 0, R = nn + 1, mid;
while(L + 1 < R){
mid = (L + R) >> 1;
if(!solve(mid)) L = mid;
else R = mid;
}
cout << L + 1;
return 0;
}

浙公网安备 33010602011771号