中位数与二分->以至于第k大数与二分

中位数与二分->以至于第k大数与二分

Above the Median[USACO 2011 November Gold]一题中,要求求出中位数大于等于x的区间个数。

我们将大于等于x的数记为1,其他记为0。当一个区间的和大于等于区间长度的一半时,那么这个区间的中位数就大于等于x了。

同样的,对于Quality of Living[IOI 2010],考虑二分答案中位数小于等于x可不可能。对整体区间做上述操作,于是对于每一个区间我们只要判断区间中1的个数是否小于区间的一半,可以用二维前缀和完成。复杂度 O(n2logn2)

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<ctype.h>
#define M 1005
using namespace std;
int r,c,h,w;
int A[M][M],sum[M][M];
void Rd(int &res){
    char c;res=0;
    while(c=getchar(),!isdigit(c));
    do{
        res=(res<<1)+(res<<3)+(c^48);
    }while(c=getchar(),isdigit(c));
}
bool check(int x){
    int cnt=h*w/2;
    for(int i=1;i<=r;i++)
        for(int j=1;j<=c;j++)
            sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+(A[i][j]>x);
    for(int i=h;i<=r;i++)
        for(int j=w;j<=c;j++)
            if(sum[i][j]+sum[i-h][j-w]-sum[i-h][j]-sum[i][j-w]<=cnt)return true;
    return false;
}
int main(){
//  freopen("quality.in","r",stdin);
//  freopen("quality.out","w",stdout);
    Rd(r);Rd(c);Rd(h);Rd(w);
    for(int i=1;i<=r;i++)
        for(int j=1;j<=c;j++)
            Rd(A[i][j]);
    int L=1,R=r*c,res;
    while(L<=R){
        int mid=(L+R)>>1;
        if(check(mid)){
            res=mid;
            R=mid-1;
        }else L=mid+1;
    }
    printf("%d\n",res);
    return 0;
}

同样如果把这个推至第k大值也是相同的,值得借鉴的是这个二分的想法:中位数小于等于x是否可能

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值