[二分] [思维] 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;
}

posted @ 2026-01-12 20:13  Zwi  阅读(1)  评论(0)    收藏  举报