POJ 3679 Median 【二分】

題目鏈接

題意

給N(N小於等於1e6)個數,求出由它們每個數的差組成的數列的中位數(若有偶數個,取左邊的一個)

分析

1e6的數據量,直接算是O(n2) 的數據量,肯定T。考慮用二分來枚舉中位數。然後二分中的判斷有不同的方法:

1.O(nlog2n) 做法:
用兩次二分。先把原來的所有數排序,排序之後,選定一個數,其後面的數與其的差就是遞增的了。於是用枚舉的中位數,從頭到尾遍歷,對於遍歷到的每一個數,找到有多少數從這個數開始是小於它加上枚舉出的中位數的(也即差小於這個中位數),求和就可以判斷有多少差值是小於這個枚舉出的數了。
這裏雖然思路清晰,但是極易寫錯。同時要考慮這個這個枚舉出來數可能有多個。同時,用longlong會T,以後記住int的範圍在40億左右,能用int就用int。將代碼貼在這裏,以備參考:

//判斷函數
bool valid(int a)
{
    int sum=0;
    for(int i=0;i<n-1;++i)
        sum+=upper_bound(X+i+1,X+n,X[i]+a)-(X+i+1);
    --sum;
    return sum>=m;
}
//二分
while(a<b-1)
{
    mid=(a+b)/2;
    if(valid(mid)) b=mid;
    else a=mid;
}
cout<<b<<endl;

2.O(nlogn) 做法
在判斷那裏不用二分,而改用滑動窗口,其實這樣還好寫一點……(先下面AC代碼)

AC代碼

//POJ 3579 Median
//AC 2016-8-1 11:33:35
//Binary Search, Two Pointers
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cctype>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <set>
#include <string>
#include <map>
#include <queue>
#include <deque>
#include <list>
#include <sstream>
#include <stack>
using namespace std;

#define cls(x) memset(x,0,sizeof x)
#define inf(x) memset(x,0x3f,sizeof x)
#define neg(x) memset(x,-1,sizeof x)
#define ninf(x) memset(x,0xc0,sizeof x)
#define st0(x) memset(x,false,sizeof x)
#define st1(x) memset(x,true,sizeof x)
#define INF 0x3f3f3f3f
#define lowbit(x) x&(-x)
#define bug cout<<"here"<<endl;
//#define debug

int n;
int X[1000100],m;

bool valid(int a)
{
    int sum=0;
    int p=0,q=0;
    for(p=0;p<n-1;++p)
    {
        while(q<n&&abs(X[q]-X[p])<=a)
            ++q;
        if(q==p) break;
        sum+=q-p-1;
    }
    --sum;
    return sum>=m;
}


int main()
{
    #ifdef debug
        freopen("E:\\Documents\\code\\input.txt","r",stdin);
        freopen("E:\\Documents\\code\\output.txt","w",stdout);
    #endif
    while(scanf("%d",&n)!=EOF)
    {
        m=n;m*=n-1;m/=2;
        if(m&1) m/=2;
        else m=m/2-1;
        for(int i=0;i<n;++i)
            scanf("%lld",&X[i]);
        sort(X,X+n);
        int a=0,b=1000001000,mid;
        while(a<b-1)
        {
            mid=(a+b)/2;
            if(valid(mid)) b=mid;
            else a=mid;
        }
        cout<<b<<endl;
    }
    return 0;
}
發佈了54 篇原創文章 · 獲贊 3 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章