当前位置: 首页 > news >正文

AtCoder - arc101_b Median of Medians 分析与解答

Median of Medians - AtCoder arc101_b - Virtual Judge

寻找中位数们的中位数,使用二分搜索,在数列a的最小值和最大值之间搜索,

在一列数m1,m2,m3......m_n中,如果x是他们的中位数,应该满足大于等于x的数的数目大于等于

n-[n/2],并且x是满足该条件的最大数

比如1,2,3,4中,x=3是满足两个数(4-[4/2])大于等于x的最大x值

比如 1,2,3,4,5中,x=3是满足三个数(5-[5/2])大于等于x的最大x值

所以可以统计,在所有的中位数中,满足大于等于x的数的个数

如果统计给定一个区间[l,r],快速判断这个区间的中位数是否大于等于x呢:

通过观察,将这个区间的数不降序排列后,如果区间内大于等于x的数的数目(区间中数的个数为n)大于等于(n-[n/2]),则该区间的中位数大于等于x

比如1 2 3 4,x=3,大于等于3的个数是2=4-[4/2]

比如1 2 3 4 5,x=3,大于等于3的个数是3=5-[5/2]

将一个区间中的数分成两类,大于等于x的数令其为1,否则令其为-1,则当这个区间的数的和大于等于0的时候,这个区间的中位数大于等于x

例如1 2 3 4,变为 -1 -1 1 1,和为0

这样处理后,求一个区间的和可以通过前缀和快速计算,给定区间端点l和r,如果pref[r]-pref[l-1]>=0,则这个区间的中位数大于等于x

通过移项得到 pref[r]>=pref[l-1],(r>=l>l-1),也就是在pref数组中出现几个逆序对就有几个区间的中位数不大于等于x

因为l=1时,l-1=0,所以pref数组对于逆序对的计数要从下标0开始,统计逆序对的方法有归并排序和树状数组

复杂度 log(10^9)(二分查找)*Nlog(N)(使用树状数组)

#include<iostream>
#include<cstdio>
#include<climits>
#include<cstring>
using namespace std;

#define int long long
#define lowbit(x) (x&(-x))

const int maxn=2*1e5+5;

int tree[maxn],a[maxn],pref[maxn];
int n;

void update(int x,int d){
    while(x<=maxn){
        tree[x]+=d;
        x+=lowbit(x);
    }
}

int query(int x){
    int res=0;
    while(x){
        res+=tree[x];
        x-=lowbit(x);
    }
    return res;
}

int satisfy(int x){
    memset(tree,0,sizeof(tree));
    int t=n*(n+1)/2;        //总数目
    int tar=t-t/2;          //顺序对数目应该大于等于这个数
    int cnt=0;
    int minpref=0;
    pref[0]=0;
    for(int i=1;i<=n;i++){
        pref[i]=pref[i-1];
        if(a[i]>=x){
            pref[i]++;
        }else {
            pref[i]--;
        }
        minpref=min(minpref,pref[i]);
    }
    int base=-minpref+1;
    for(int i=0;i<=n;i++){
        pref[i]+=base+1;
    }

    for(int i=n;i>=0;i--){
        cnt+=query(pref[i]-1);
        update(pref[i],1);
    }
    if(t-cnt>=tar){
        return 1;
    }else {
        return 0;
    }
}



int bin_search(int l,int r){
    int ans=-1;
    while(l<r){
        int mid=(l+r)>>1;
        //printf("l=%lld r=%lld mid=%lld\n",l,r,mid);
        if(satisfy(mid)){
            //printf("%lld满足!\n",mid);
            ans=mid;
            l=mid+1;
        }else {
            r=mid;
        }
    }
    return ans;
}


signed main()
{
    ios::sync_with_stdio(0);cin.tie(0);

    cin>>n;
    int maxa=-1,mina=INT_MAX;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        maxa=max(maxa,a[i]);
        mina=min(mina,a[i]);
    }
    cout<<bin_search(mina,maxa+1)<<"\n";
    return 0;
}

相关文章:

  • 2009年下半年软件设计师上午真题的知识点整理(附真题及答案解析)
  • Kubernetes-master 组件
  • 25/2/16 <算法笔记> MiDas原理
  • ElasticSearch详解
  • 【开源免费】基于Vue和SpringBoot的美食烹饪互动平台(附论文)
  • 【HUSTOJ 判题机源码解读系列03】judge.cc 源码详细注释
  • 端到端测试利器:Playwright入门教程
  • 力扣 66.加一 (Java实现)
  • ROS应用之SwarmSim在ROS 中的协同路径规划
  • Baklib全场景云平台:一站式知识管理赋能企业效能升级
  • C++11 thread
  • 大模型应用开发书籍推荐
  • 对项目交接的一些思考
  • 通用知识库问答流程
  • vue2.0接入海康威视控件包V3.3.0——海康威视摄像头接入前端页面(webSDK包)模式
  • 【STM32】外部时钟|红外反射光电开关
  • 40、【OS】【Nuttx】OSTest分析(4):内存监控(二)
  • Python进制转换
  • inline关键字
  • effective-Objective-C第六章阅读笔记
  • 咸宁市委常委、市纪委书记官书云调任湖北省司法厅副厅长
  • 面对非专业人士,科学家该如何提供建议
  • 人民日报钟声:平等对话是解决大国间问题的正确之道
  • 碧桂园服务:拟向杨惠妍全资持有的公司提供10亿元贷款,借款将转借给碧桂园用作保交楼
  • 李云泽:再批复600亿元,进一步扩大保险资金长期投资试点范围
  • 刘诚宇、杨皓宇进球背后,是申花本土球员带着外援踢的无奈