zoukankan      html  css  js  c++  java
  • 【HIHOCODER 1133】 二分·二分查找之k小数

    描述


    在上一回里我们知道Nettle在玩《艦これ》,Nettle的镇守府有很多船位,但船位再多也是有限的。Nettle通过捞船又出了一艘稀有的船,但是已有的N(1≤N≤1,000,000)个船位都已经有船了。所以Nettle不得不把其中一艘船拆掉来让位给新的船。Nettle思考了很久,决定随机选择一个k,然后拆掉稀有度第k小的船。 已知每一艘船都有自己的稀有度,Nettle现在把所有船的稀有度值告诉你,希望你能帮他找出目标船。
    提示:非有序数组的二分查找之二

    输入


    第1行:2个整数N,k。N表示数组长度,
    第2行:N个整数,表示a[1..N],保证不会出现重复的数,1≤a[i]≤2,000,000,000。

    输出


    第1行:一个整数t,表示t在数组中是第k小的数,若K不在数组中,输出-1。

    样例输入

    10 4
    1732 4176 2602 6176 1303 6207 3125 1 1011 6600
    

    样例输出

    1732
    

    题解


    利用类似快速排序的方法将问题区间不停二分,期望情况是($n +frac n 2 +frac n 4 +frac n 8 + dots+1 $)即(2n),随机化基准数即可。

    每一次我们随机从数组中选取一个数m,将比m小的数从a[1]开始放置,将比m大的数从a[N]开始放置。当其他所有的数都放置完成后。最后剩下的格子放置m,不妨设为a[Mid], 则在我们进行一次遍历交换以后有如下性质:
    若k<Mid,则有第k小的数一定在a[L..Mid-1]之中,令R = Mid - 1
    若k=Mid,则m就是我们要找的数
    若k>Mid,则第k小的数一定在a[Mid+1..R]之中,令L = Mid + 1。此处需特别注意,在a[Mid+1..R]我们查找的k'和原来的k不相同,现在的k'=k-Mid。

    #include <vector>
    #include <queue>
    #include <cstdio>
    #include <complex>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #define ll long long
    #define inf 1000000000
    #define PI acos(-1)
    #define bug puts("here")
    #define REP(i,x,n) for(int i=x;i<=n;i++)
    #define DEP(i,n,x) for(int i=n;i>=x;i--)
    #define mem(a,x) memset(a,x,sizeof(a))
    typedef unsigned long long ull;
    using namespace std;
    inline int read(){
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    inline void Out(int a){
        if(a<0) putchar('-'),a=-a;
        if(a>=10) Out(a/10);
        putchar(a%10+'0');
    }
    const int N=1e6+5;
    int a[N];
    int main(){
        int n=read(),m=read();
        REP(i,1,n) a[i]=read();
        int l=1,r=n,ans=-1;
        while(l<=r){
            int w=rand()%(r-l+1)+l;
            swap(a[l],a[w]);
            int tmp=a[l],tl=l,tr=r;
            while(tl<tr){
                while(tl<tr&&a[tr]>=tmp) tr--;
                a[tl]=a[tr];
                while(tl<tr&&a[tl]<=tmp) tl++;
                a[tr]=a[tl];
            }
            a[tl]=tmp;
            if(tl==m) {ans=a[tl];break;}
            else if(tl>m) r=tl-1;
            else l=tl+1;
        }
        printf("%d
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    【Java8新特性】你知道Java8为什么要引入Lambda表达式吗?
    你说你懂计算机网络,那这些你都知道吗
    程序员需要了解的硬核知识之控制硬件
    程序员需要了解的硬核知识之汇编语言(全)
    真的,Kafka 入门一篇文章就够了
    程序员需要了解的硬核知识之汇编语言(一)
    带你涨姿势的认识一下 Kafka 消费者
    程序员需要了解的硬核知识之操作系统和应用
    详解Kafka Producer
    程序员需要了解的硬核知识之操作系统入门
  • 原文地址:https://www.cnblogs.com/zsyacm666666/p/7627051.html
Copyright © 2011-2022 走看看