poj 3579

/*

    描述:
        给定n个数字,求所有两两数字之差的绝对值的中位数。
        可知,共有n*(n-1)/2=m个数字。

    解析:
        因为满足性质——假如对key可以找出>m/2个数字>=key,那么对于任意key‘,
        有 key‘ <= key -> key‘亦满足性质
        所以利用这个性质进行二分答案

        ans是最终答案,也是最后一个满足性质的数字
        对val,如果满足性质,那么val<=ans,否则val>ans

        从0到最大值是范围。(left,right)
        test(val)——可以找出来>m/2个数字>=val(因为必须包含val自身,所以必然>m/2)
            ——假如可以,那么答案在集合[val,right)中
            ——不可以,说明目前val过大了,答案在集合(left,val)中

        test(val)
        range(c,1,n)
        {
            ans += n - (lower_bound(a,a+n,a[c]+val)-a);
            //找到第一个和目前差值>-=val的,计算总共有多少个这样的数字
        }
        return ans > m/2;
*/
#include <cstdio>
#include <iostream>
#include <algorithm>
#define range(i,a,b) for (int i=a;i<=b;i++)

using namespace std;

const int maxn = 100000;

int a[maxn+1];
int n;
int m;

bool test(int val)
{
    int ans(0);
    range(c,0,n-1)
    {
        ans += n - (lower_bound(a,a+n,a[c]+val) - a);
    }
    return ans > m;
}

void Work(int n)
{
    m = (n-1)*n/4;
    range(i,0,n-1)
    {
        scanf("%d",&a[i]);
    }

    sort(a,a+n);

    int l(0),r(a[n-1]-a[0]);//注意r的初始化,直接为a[n-1]有点大

    while(l+1<r)//必须如此,不然超时
    {
        int mid = (l+r)>>1;
        if (test(mid))
        {
            l = mid;
        }
        else
        {
            r = mid;
        }
    }
    if (test(r))
    {
        cout<<r<<endl;
    }
    else
    {
        cout<<l<<endl;
    }
}

int main()
{
    while(cin>>n)
    {
        Work(n);
    }

    return 0;
}
时间: 2024-10-18 20:22:03

poj 3579的相关文章

poj 3579 Median 二分查找与lower_bound

题意: 给n个数,他们两两之间较大数减去较小数总共有n*(n-1)/2个数,要求这些数的中位数. 分析: 两次二分,第一次枚举答案,第二次判断该数是否可能成为中位数. 代码: //poj 3579 //sep9 #include <iostream> #include <algorithm> using namespace std; const int maxN=1e5+10; int a[maxN]; int n,m; int test(int x) { int sum=0; f

POJ 3579 3685(二分-查找第k大的值)

POJ 3579 题意 双重二分搜索:对列数X计算∣Xi – Xj∣组成新数列的中位数 思路 对X排序后,与X_i的差大于mid(也就是某个数大于X_i + mid)的那些数的个数如果小于N / 2的话,说明mid太大了.以此为条件进行第一重二分搜索,第二重二分搜索是对X的搜索,直接用lower_bound实现. #include <iostream> #include <algorithm> #include <cstdio> #include <cmath&g

POJ 3579 Median 二分+思维

POJ 3579 Median 二分+思维 题意 给你一些数,然后求这些数相互之间差的绝对值,然后绝对值排序,找到中间那个数. 解题思路 我反正一直开始是没有想到这个题竟然可以用二分来做.━━( ̄ー ̄*|||━━. 二分枚举答案,假设枚举值为mid,然后就是在排好序的序列中对每一个num[i]找到在i之后,有多少个大于num[i]+mid的数的个数(数列里的值比num[i]+mid大,说明该值与num[i]作差形成的新数列里的数比中位数mid大),用lower_bound计算所有差值比mid大于

POJ 3579 Median(二分答案+Two pointers)

[题目链接] http://poj.org/problem?id=3579 [题目大意] 给出一个数列,求两两差值绝对值的中位数. [题解] 因为如果直接计算中位数的话,数量过于庞大,难以有效计算, 所以考虑二分答案,对于假定的数据,判断是否能成为中位数 此外还要使得答案尽可能小,因为最小的满足是中位数的答案,才会是原差值数列中出现过的数 对于判定是不是差值的中位数的过程,我们用尺取法实现. 对于差值类的题目,还应注意考虑边界,即数列只有一位数的情况. [代码] #include <cstdio

poj 3579 Median (二分搜索之查找第k大的值)

Description Given N numbers, X1, X2, ... , XN, let us calculate the difference of every pair of numbers: ∣Xi - Xj∣ (1 ≤ i < j ≤ N). We can get C(N,2) differences through this work, and now your task is to find the median of the differences as quickly

Divide and conquer:Median(POJ 3579)

    快速求两数距离的中值 题目大意:给你一个很大的数组,要你求两个数之间的距离的中值 二分法常规题,一个pos位就搞定的事情 1 #include <iostream> 2 #include <algorithm> 3 #include <functional> 4 5 using namespace std; 6 typedef long long LL_INT; 7 8 static int nums[100002]; 9 bool judge(LL_INT,

POJ - 3579 Median 二分

题目大意:给出n个数,要求将这n个数两两相减,把这些相减得到的数排序后,输出位置在中间的那个数 解题思路:如果两两相减再排序复杂度太高,肯定超时了,不妨换另一种思路 枚举最中间的那个数,然后判断一下相减得到的数有多少个大于等于枚举的数 如何判断上面所说的那句呢,其实不用把每个数相减,只需要排序一下,然后将当前这个数 + 枚举的那个数,然后在数组中找到大于等于这个数的第一个位置(lower_bound()),再用n减去那个数的位置就可以知道有多少个相减的结果会大于等于这个数了 最后只需要判断一下大

POJ 3579解题记录

二分中值,检查的时候继续二分,二分套二分..... #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<functional> #include<queue> using namespace std; typedef long long ll; const int maxv=1e5+30; ll n; ll tol; ll

【POJ - 3579 】Median(二分)

Median Descriptions 给N数字, X1, X2, ... , XN,我们计算每对数字之间的差值:∣Xi - Xj∣ (1 ≤ i < j ≤N). 我们能得到 C(N,2) 个差值,现在我们想得到这些差值之间的中位数. 如果一共有m个差值且m是偶数,那么我们规定中位数是第(m/2)小的差值. Input 输入包含多测每个测试点中,第一行有一个NThen N 表示数字的数量.接下来一行由N个数字:X1, X2, ... , XN( Xi ≤ 1,000,000,000  3 ≤