AT2165 Median Pyramid Hard [二分答案]

M e d i a n   P y r a m i d   H a r d Median\ Pyramid\ Hard Median Pyramid Hard


最 初 想 法 \color{blue}{最初想法}

每次往上走, 最小值 与 最大值 都不会往上传, 于是就以为每次将最大值最小值去掉就好了, 即输出中位数…

错 因 : 错因: : 往上走时, 可能有数字重复地往上走, 出现了重复, 每次上去的就不一定是极值了.

正 解 部 分 \color{red}{正解部分}

二分答案,
设二分出的答案为 m i d mid mid,
则将原来的三角形中 大于等于 m i d mid mid 的数字设为 1 1 1, 其余设为 0 0 0 .

规 律 : 若 存 在 两 个 相 邻 的 相 同 数 字 , 则 往 上 将 继 续 出 现 两 个 相 同 数 字 相 邻 的 形 势 . 规律:若存在两个相邻的相同数字, 则往上将继续出现两个相同数字相邻的形势. :,.

L u o g u Luogu Luogu 题解上的图.

观察图可知, 哪种连续的数字离中轴较近, 则第一层为那种数字 .

于是只需要 O ( N ) O(N) O(N) 判断哪种数字离中轴最近即可 .

加上二分 总时间复杂度 O ( N l o g N ) O(NlogN) O(NlogN) .

特 殊 情 况 : 特殊情况: :

同样是 L u o g u Luogu Luogu 题解上的图

这个时候没有连续的 0 0 0 1 1 1, 只需要看第一个元素是什么就可以了.


实 现 部 分 \color{red}{实现部分}

c h e c k 函 数 : check函数: check:

判断时可以不需要从左向右不断取 min ⁡ \min min 求最小值 .

可以直接从小到大枚举距离, 若有连续的数字, 直接返回即可,
若始终没有连续的数字, 为特殊情况, 特殊处理.

左 右 端 点 的 移 动 : 左右端点的移动: :

  • 若第 1 1 1 层为 1 1 1, 说明 真正答案 大于等于 x x x, 需要将二分左端点右移.
  • 反之 右端点 左移.
#include<bits/stdc++.h>
#define reg register

const int maxn = 2e5 + 5; //!

int N;
int A[maxn];
int B[maxn];

bool chk(int x){
        for(reg int i = 1; i <= 2*N-1; i ++) B[i] = (A[i]>x);
        for(reg int d = 1; d < N; d ++)
                if((B[N+d-1]&&B[N+d]) || (B[N-d+1]&&B[N-d])) return 1;
                else if(((!B[N+d-1])&&(!B[N+d])) || ((!B[N-d+1])&&(!B[N-d]))) return 0;
        return B[1];
}

int main(){
        scanf("%d", &N);
        for(reg int i = 1; i <= 2*N-1; i ++) scanf("%d", &A[i]);
        int l = 1, r = 2*N-1;
        while(l < r){
                int mid = l+r >> 1;
                if(chk(mid)) l = mid + 1;
                else r = mid;
        }
        printf("%d\n", l);
        return 0;
}

W h y   W a ? ↓ \color{red}{Why\ Wa?↓} Why Wa?

#include<bits/stdc++.h>
#define reg register

const int maxn = 2e5 + 5; //!

int N;
int A[maxn];
int B[maxn];

bool chk(int x){
        for(reg int i = 1; i <= 2*N-1; i ++) B[i] = (A[i]>=x);
        for(reg int d = 1; d < N; d ++)
                if((B[N+d-1]&&B[N+d]) || (B[N-d+1]&&B[N-d])) return 1;
                else if(((!B[N+d-1])&&(!B[N+d])) || ((!B[N-d+1])&&(!B[N-d]))) return 0;
        return B[1];
}

int main(){
        scanf("%d", &N);
        for(reg int i = 1; i <= 2*N-1; i ++) scanf("%d", &A[i]);
        int l = 1, r = 2*N-1;
        while(l < r){
                printf("%d %d\n", l, r);
                int mid = l+r >> 1;
                if(chk(mid)) l = mid;
                else r = mid - 1;
        }
        printf("%d\n", l);
        return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值