[POJ 3579] Median (二分答案+二分查找)

POJ - 3579
有一个序列,其中每两个数相减的绝对值组成的新序列,新序列排序后处于中间的那个值是多少
显然一个是要二分答案,然后统计答案是大了还是小了,但是统计需要点技巧
首先对原序列排个序
二分出答案 ans,然后判断差小于 ans的方案数
对每个 ai统计小于 ai+ans的有多少个,方式就是枚举 ai
然后二分 ai以后的区间,统计出来再累加起来
时间复杂度 O(logn*nlogn)

#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
#include <set>
#include <queue>
using namespace std;
typedef pair<int,int> Pii;
typedef long long LL;
typedef unsigned long long ULL;
#define MST(a,b) memset(a,b,sizeof(a))
#define CLR(a) MST(a,0)
#define Pow2(a) a*a
int maxx(int a,int b){return a>b?a:b;}
int minn(int a,int b){return a<b?a:b;}
int abss(int a){return a<0?(-a):a;}

const int maxn=1e5+10;
const int INF=1e9+10;
int N;
int inpt[maxn];

LL Cnt(int);

int main()
{
    while(~scanf("%d", &N))
    {
        for(int i=1; i<=N; i++) scanf("%d", &inpt[i]);
        sort(inpt+1,inpt+1+N);
        LL M=((LL)(N-1)*N/2+1)/2;
        int l=0,r=INF;
        while(l<r)
        {
            int mid=(l+r)>>1;
            if(Cnt(mid)>=M) r=mid;
            else l=mid+1;
        }
        printf("%d\n", l);
    }
    return 0;
}

LL Cnt(int dist)
{
    LL res=0;
    for(int i=1; i<=N; i++)
    {
        int l=i,r=N;
        while(l<r)
        {
            int mid=(l+r+1)>>1;
            if(inpt[mid]-inpt[i]<=dist) l=mid;
            else r=mid-1;
        }
        res+=r-i;
    }
    return res;
}

你可能感兴趣的:(poj)