POJ 3579 —— Median

题目来源:http://poj.org/problem?id=3579

二分答案+尺取。

首先想到要对数列进行排序。

先二分差值的中位数x,然后找出小于x的所有差值的个数以及所有大于x的差值的个数,这个过程可以用尺取法。

同时统计出差值=x的差值个数t。若t=0,则这个mid不可能是答案。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
using namespace std;
const int maxn=1e5+10;
int n;
ll a[maxn];
ll up(ll x)
{
    ll tot=0;
    int r=2;
    for(int l=1;l<=n;++l)
    {
        while(r<=n&&a[r]-a[l]<=x)
            r++;
        if(r>n)break;
        tot+=n-r+1;
    }
    return tot;
}
ll down(ll x)
{
    int tot=0;
    int l=1;
    for(int r=2;r<=n;++r)
    {
        while(l<r&&a[r]-a[l]>=x)
            ++l;
        tot+=r-l;
    }
    return tot;
}
int main()
{
    while(~scanf("%d",&n))
    {
        for(int i=1;i<=n;++i)
            scanf("%lld",&a[i]);
        sort(a+1,a+1+n);
        ll tot=n*(n-1)/2;
        ll l=0,r=a[n];
        ll ans=0;
        ll m=(tot+1)/2;
        while(l<=r)
        {
            ll mid=(l+r)/2;
            ll u=up(mid),d=down(mid);
            ll t=tot-u-d;
            if(t==0)
            {
                if(d>=m)r=mid-1;
                else l=mid+1;
                continue;
            }
            if(d<m)
            {
                if(d+t>=m)
                {
                    ans=mid;
                    break;
                }
                else l=mid+1;
            }
            else r=mid-1;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值