把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

[AGC006D] Median Pyramid Hard 题目分析

[AGC006D] Median Pyramid Hard 题目分析

评价

一道非常好的思维题目!!!

分析

注意到:从三个数选一个中位数。

似乎没有什么好的方法,但是每一层的迭代有一种相似方法。

我们假设一个答案。

将大于等于答案的标记为 \(1\),其他的为 \(0\)

三——一个非常重要的数,我们要考虑以下:

全是0:000 -> 0
一个1:001 -> 0
两个1:101 -> 1
三个1:111 -> 1

我们发现得到的答案取决于数量(\(0\) 多还是 \(1\) 多)。

那我们怎么确定他能一直走到尾呢?

注意到:

 ???        ----->     00?
x00zy                 x00zy

也就是说,两个连续的在一起,能够使得上面也一样(但是要看边界)。

注意到要是中间有连续的(即最靠近中间的一段 \(0\) 或者 \(1\))说明顶尖就是大于等于数字。

我们发现这样具有单调性,于是乎可以考虑二分答案解决。

然后我们就很好的解决了该问题。

总时间复杂度 \(\mathcal{O}(n\log n).\)

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <stdlib.h>
#include <cstring>
#include <vector>
#define N 100005
using namespace std;
int a[N << 2],n,b[N << 2];
bool check(int x) {
	for (int i = 1;i <= 2 * n - 1;i ++) b[i] = (a[i] >= x);
	for (int dis = 0;dis < n - 1;dis ++) {
		if (b[n + dis] == b[n + dis + 1]) return b[n + dis];
		if (b[n - dis] == b[n - dis - 1]) return b[n - dis];
	}
	return b[1];
}
signed main(){
	cin >> n;
	for (int i = 1;i <= 2 * n - 1;i ++) cin >> a[i];
	int l = 1,r = 2 * n - 1,res = r;
	while(l <= r) {
		int mid = l + r >> 1;
		if (check(mid)) res = mid,l = mid + 1;
		else r = mid - 1;
	}
	cout << res;
	return 0;
} 

拓展:如何去掉 \(\log\)

我们可以通过二分算法得到线性算法,这是一个好方法。

我们发现我们得到一个对的值那么我们只需要扫一遍就可以了。那么这个对的值就是 \(1\),改变成 \(2\) 只需要改变原本 \(1\) 的位置,判断也只需要往中间判断是否有连续的 \(0\) 即可。

posted @ 2025-02-09 12:19  high_skyy  阅读(26)  评论(0)    收藏  举报
浏览器标题切换
浏览器标题切换end