POJ

来源:互联网 发布:闲鱼假货淘宝介入 编辑:程序博客网 时间:2024/06/12 00:20

问题描述
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 as you can!

Note in this problem, the median is defined as the (m/2)-th smallest number if m,the amount of the differences, is even. For example, you have to find the third smallest one in the case of m = 6.

Input
The input consists of several test cases.
In each test case, N will be given in the first line. Then N numbers are given, representing X1, X2, … , XN, ( Xi ≤ 1,000,000,000 3 ≤ N ≤ 1,00,000 )

Output
For each test case, output the median in a separate line.

Sample Input

41 3 2 431 10 2

Sample Output

18

分析:

这题如果真正把C(n,2) 每个情况都枚举一下,然后排个序最后查询第m小值,一定会超时的。所以分析此题是要求第m小的值,那么就可以采用二分法

具体步骤:先将序列a排序,因为要查询第m小的值,则对确定的d,通过枚举第一个元素的下标来统计以这个元素为首的序列中有多少个是满足a[j] - a[i] <= d 的。

这里注意一下(理解了好久):

  • a[j] - a[i] <= d (这里是题目要求的,d为确定的第m小的值
  • a[j]<= a[i] + d (通过上面式子转换而成),那么依据此式统计序列中小于a[i]+d即a[j]的个数即可。用upper_bound来统计,注意:要除去a[i]本身哦,所以每次统计结果要减一

举个例子:
比如序列a 为 1, 2, 3, 4 。那么m的值为3。
aj-ai后的新序列为1,1,1,2,2,3。则最后的结果应该是第3小的数即1。
那么通过我们上面的分析,如果假设第3小的数d为2,我们试着判断一下

从1开始的序列 即1,2,3,4 。统计小于等于1+2=3的个数,除去1,为2和3两个数从2开始的序列 即2,3,4   。统计小于等于2+2=4的个数,除去2,为3和4两个数从3开始的序列 即3,4     。统计小于等于3+2=5的个数,除去3,为4一个数从4开始的序列 即4       。统计小于等于4+2=6的个数,除去4,则为0这样累加个数为 2 + 2 + 1 + 0 = 5, 5 > m=3 ,则缩小范围那么继续判断d = 1是否满足

用C(d)函数来统计判断:这里的C(d)是,统计序列a中小于等于ai+d的个数(每次减一),然后累加,从而计算出有多少个数对的差值是小于等于d的,如果大于m的话则d值弄大了,如果小于m的话,说明这个d根本达不到第m个数。如此二分确定最后的值。

代码如下:

#include<cstdio>#include<algorithm>using namespace std; const int maxn = 100000+10;const int INF = 1000000000;int N, M;int a[maxn];bool C(int d){    int cnt = 0;    for(int i=0; i<N; i++)    {        cnt += (upper_bound(a+i, a+N, a[i]+d)-1 - (a+i));       }    if(cnt >= M) return true;    else return false;}void solve(){    int c = N * (N-1) / 2;    if(c%2==0) M = c/2;    else M = c/2+1;    sort(a, a+N);    int lb = 0, ub = INF;    while(ub - lb > 1)    {        int mid = (lb + ub) / 2;        if(C(mid)) ub = mid;        else lb = mid;     }    printf("%d\n",ub);} int main(){    while(scanf("%d",&N)!=EOF)    {        for(int i=0; i<N; i++)        {            scanf("%d",&a[i]);        }        solve();    }    return 0;}
1 0
原创粉丝点击