题解 SP18939 【KSMALL - K-th smallest number】

发现提交记录全用的是nth_element...(真就STL依赖症?)

提供一种 \(\mathcal O(n)\) 的二分算法。

Solution

我们可以用类似快排的方式。在快排的分治中,若双指针(\(i,j\))已经扫描完这段区间 \([l,r]\),即 \(i\) 已经大于 \(j\),就会把它分为三部分:\([l,j],(j,i),[i,r]\)。然后判断 \(k\) 的位置,如果在 \([l,j]或[i,r]\),就二分,否则答案就是 \((j,i)\) 的第一个数 \(array_{j+1}\)

Code

#include<bits/stdc++.h>
using namespace std;
unsigned d[5000005];
void randomize(unsigned a,unsigned b,unsigned mod)
{
    for( int i=0 ; i<5000000 ; i++ )
    {
        a = 31014 * (a & 65535) + (a >> 16);
        b = 17508 * (b & 65535) + (b >> 16);
        d[i] = ((a << 16) + b) % mod;
    }
}
int k;
unsigned find(int l,int r) {
    unsigned x=d[(l+r)/2];
    int i=l,j=r;
    do{//类快排部分
        while(d[i]<x)i++;
        while(d[j]>x)j--;
        if(i<=j)swap(d[i],d[j]),i++,j--;
    }while(i<=j);//双指针扫描
    if(k<=j)return find(l,j);
    else if(i<=k)return find(i,r);
    else return d[j+1];
}
int main(){
    unsigned a,b,mod;
    scanf("%u%u%u%d",&a,&b,&mod,&k);
    randomize(a,b,mod);k--;
    printf("%u\n",find(0,4999999));
    return 0;
}
posted @ 2020-12-03 23:00  ADay526  阅读(130)  评论(0)    收藏  举报