[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\) 即可。