AT2165 中位数金字塔 笔记
yixinxiangxue172 · · 题解
题目传送门
solution
我们需要求的是每组的中位数,所以记录大小关系是很重要的(废话。
对于一个数字
以样例为例,当
把这个性质向上推,就有一种情况:当
可以知道只要一直往上推,直到塔尖,这个性质依然适用。那么有这么多的
那怎样找到这个
code
#include <cstdio>
#include <cstring>
int N, Ans, A[200001], B[200001];
namespace S {
inline bool Min(int w1, int w2, int d) {
return A[w1] <= d && A[w2] <= d;
//两个是否都是小于等于当前值
}
inline bool Max(int w1, int w2, int d) {
return A[w1] > d && A[w2] > d;
//两个是否都是大于当前值
}
inline int check(int x) {
int Mid = N / 2 + 1; //中间点(塔顶对于塔底数列是第几个)
for(int i = 0; i < Mid - 1; i ++) {
/*
制作 01 序列:从中间往边上找有没有 00 或 11
就可以找到最靠中间的两个相同的,像解释中那样
*/
if(Max(Mid - i, Mid - i - 1, x) || Max(Mid + i, Mid + i + 1, x)) {
return 1;
}
if(Min(Mid - i, Mid - i - 1, x) || Min(Mid + i, Mid + i + 1, x)) {
return 0;
}
}
return !(A[1] <= x);
//特判没有 00 , 11 时的情况,此时易得塔顶应为第一个或最后一个 0 或 1
}
inline int read() { //读入优化
int cnt = 1, res = 0;
char ch = getchar();
while(ch < '0' || ch > '9') {
cnt = ch == '-' ? -1 : 1, ch = getchar();
}
while(ch >= '0' && ch <= '9') {
res = res * 10 + (ch ^ 48), ch = getchar();
}
return res * cnt;
}
inline void print(int x) {
if(x < 0) putchar('-'), x = -x;
x > 9 ? print(x / 10), putchar((x % 10) ^ 48) : putchar((x % 10) ^ 48);
}
inline void Erfen() { //二分寻找 x 作为候选答案
int l = 1, r = N; //因为 N 已是 N * 2 - 1,所以 r 直接赋值为 N
while(l < r) { //因为要求的是最后一个小于等于的,所以是用右标记查找
int Mid = (l + r) / 2; //二分查找中的中间值
int p = check(Mid); //判断塔顶答案是否比 x 大
if(p == 0) {
r = Mid;
} else {
l = Mid + 1;
}
}
print(r); //找到答案,输出
}
}
using namespace S;
int main(int argc, char const * argv[]) {
memset(B, 127, sizeof(B)); //赋值为无穷大
N = read() * 2 - 1; //读入 N 的值
for(int i = 1; i <= N; i ++) {
A[i] = read();
}
Erfen(); //直接二分
return 0; //完美的结束
}
tips
如果一个 (想一想。