【poj 3579】 Median

题意:

输入一个正整数 n ,1个正整数序列A,有 n 个元素,现在定义一个新的序列B,里面的元素分别是序列 A 中任意两个数之间的差的绝对值,差的个数一共有C2n个,现在求序列 B 的中位数。如果B序列中元素的个数是偶数个,默认中位数是中间两个数中小的那一个。

思路:

计算可得中位数是 B 序列里的第k个元素,因为考虑到 n 比较大,不能构造出B序列,所以可以用二分来枚举中位数的大小。
为了方便判断二分时每次的判断,要将A序列排成升序。
每次判断,可以用两个指针 i,j 记录头和尾的位置。因为A序列是单调递增的,所以说假如 i 元素与j元素的差的绝对值小于现在二分的值,当枚举的 i 指针向后移动的时候,只会让i j 的差的绝对值减小,所以算法正确;还有,在i j 之间的每一个元素与i的差的绝对值都会满足差小于二分的值,答案直接累加,复杂度是O(n)的。
现在可以统计差值小于现在二分的答案的数有几个了,用 cnt 记录,如果小于 cnt<k ,那么这个二分的答案一定是不正确的,如果说 cntk ,那么满足这个条件最小的 cnt 一定就是答案,如果 cnt=k ,那 cnt 一定是答案;而且,就算没有 cnt=k 也没关系,因为这时一定有多个元素的差等于现在二分的答案,我们不妨看做去掉里面的几个,不影响答案。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
ll n, m, k, a1[100010];
bool check(ll x){
    ll p = 1, cnt = 0;
    for(int i = 1; i < n; i ++){
        while(p+1 <= n && a1[p+1] - a1[i] <= x) p ++;
        cnt += p-i;
    }
    return cnt < k;
}
int main(){
    while(scanf("%lld", &n) != EOF){
        m = n*(n-1)/2;
        k = (m+1)/2;
        for(int i = 1; i <= n; i ++) scanf("%lld", &a1[i]);
        sort(a1+1, a1+1+n);
        ll l = 0, r = a1[n], ans = 0;
        while(l <= r){
            int mid = (l+r)>>1;
            if(check(mid)) l = mid + 1;
            else ans = mid, r = mid - 1;
        }
        printf("%lld\n", ans);
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值