zoukankan      html  css  js  c++  java
  • poj 3579 Median 二分套二分 或 二分加尺取

    Median
    Time Limit: 1000MS   Memory Limit: 65536K
    Total Submissions: 5118   Accepted: 1641

    Description

    Given N numbers, X1X2, ... , 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 = 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 X1X2, ... , XN, ( X≤ 1,000,000,000  3 ≤ N ≤ 1,00,000 )

    Output

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

    Sample Input

    4
    1 3 2 4
    3
    1 10 2
    

    Sample Output

    1
    8

    Source

    题意:给你N个数字,求这些数字两两之差的绝对值的中位数
    二分套二分:核心还是要抓住<x的数量>=m(内层二分)最小x(外层二分)-1才是该序列中的第m小的数,有不理解的话可以看本博客另一篇讲的很详细的文章
    下面的第一份代码是使用了lower_bound,复杂度是n(logn)*(logn);时间是563ms#include<cstdio>
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <cmath>
    #include <vector>
    #include <queue>
    #include <algorithm>
    #include <set>
    using namespace std;
    #define MM(a) memset(a,0,sizeof(a))
    typedef long long LL;
    typedef unsigned long long ULL;
    const int mod = 1000000007;
    const double eps = 1e-10;
    const int inf = 0x3f3f3f3f;
    int  a[100005];
    long long   l,r,m,n;
    int ok(int  x)
    {
        int  cnt=0;
        for(int i=1;i<=n;i++)
            cnt+=lower_bound(a+i,a+n+1,a[i]+x)-(a+i)-1;
    //lower_bound降低时间复杂度 return cnt>=m; } int main() { while(~scanf("%lld",&n)) { for(int i=1;i<=n;i++) scanf("%d",&a[i]); sort(a+1,a+n+1); m=n*(n-1)/2; if(m%2==0) m=m/2; else m=(m+1)/2; l=0,r=a[n]-a[1]; while(r-l>1) { int mid=(r+l)>>1;///枚举得到<x的数量>=m的最小x; if(ok(mid)) r=mid; else l=mid; } printf("%lld ",r-1); } return 0; }

      有个小技巧是在ok()函数内统计绝对值<x的数量可以不适用lower_bound而使用尺取法

    可以降低复杂度,复杂度是(logn)*n,时间只有300多ms

    int ok(int  x)
    {
        int  cnt=0;
        for(int i=1,j=1;i<=n;i++)
              {
                  while(a[j]-a[i]<x&&j<=n)
                     j++;
                  cnt+=(j-1-i);
              }
        return cnt>=m;
    }
    

      

  • 相关阅读:
    改造MFC程序,使原来不支持winsocket的工程支持winsocket
    算术移位和逻辑移位实现分析
    MFC 编辑框中字体大小改变,行高不能改变,只能显示一半的问题,已解决。
    在MFC中,使用控制台Console输出调试信息
    在MFC中使用GDI+的一般方法,以VC6.0编译器为例
    WinForm 实现主程序(exe)与其关联类库(*.dll)分开存放
    Deserializing/Serializing SOAP Messages in C#
    List分页
    ConvertJavaMiliSecondToDateTime
    中文数字大小写转阿拉伯数字
  • 原文地址:https://www.cnblogs.com/smilesundream/p/5123626.html
Copyright © 2011-2022 走看看