Description
求数组的第k小,数字数量非常多。
Input
每组数据给出n m k表示有n个数,求第k小,数组的数字由以下规则得到:
ai = mi mod (109+7), i = 1, 2, ..., n
其中 1 ≤ n, m ≤ 5 × 107, 1 ≤ k ≤ n,数据保证得到的数组元素大部分互不相等。
Output
输出第k小的数
Sample Input
3 2 2
Sample Output
4
思路上第一可能会先想到的是:先对数组进行排序后再得到第k个数即可
#include<cstdio> using namespace std; const int mod=1e9+7; const int MAX=5e7+10; int arr[MAX]; int n,m,k; void quickSort(int left,int right){//左闭右闭 if(left>right){ return ; } int temp=arr[left];//存储对照点 int i=left,j=right; while(i<j){//从右边开始找一个小于对照点的数 while(arr[j]>=temp&&i<j){ j--; } //从左边开始找一个大于对照点的数 while(arr[i]<=temp&&i<j){ i++; } //找到后交换两个数 if(i<j){ int num=arr[i]; arr[i]=arr[j]; arr[j]=num; } } //退出循环后i=j的位置就是temp的位置 arr[left]=arr[i]; arr[i]=temp; quickSort(left,i-1);//递归左边 quickSort(i+1,right);//递归右边 } int main(){ scanf("%d%d%d",&n,&m,&k); arr[0]=m; for(int i=1;i<=n-1;i++){ arr[i] = 1LL * arr[i - 1] * m % mod;//利用前缀和读入 } quickSort(0,n-1); // for(int i=0;i<n;i++){ // printf("%d ",arr[i]); // } printf("%d\n",arr[k-1]); return 0; }
但是面对大量数据时,该算法会出现超时
因此我们需要优化,这里介绍使用快速排序来得到数组第k小数字的算法
我们知道快速排序每次都会选定一个 对照值 然后进行分区,然后将比对照值小的数放到对照值的左边,将比对照值大的数放到对照值的右边,此后该对照值的位置就不会再改变了
因此利用这一点,我们可以加以改造来求第k小的数:
如果说我们得到的对照值下标为index(下标从0开始),如果index+1刚好就等于k,说明了该对照值就是第k小个数
如果我们得到的index+1>k的话,则该对照值必然不会是第K小的数,当然,在该对照值右边的就更加不是了,因此我们可以将范围缩小到该对照值的左边
如果我们得到的index+1<k的话,则该对照值也不会是我们想要的,当然在该对照值左边比它还小的就更不是了,可以将范围缩小到该对照值下标的右边了
#include<cstdio> #include<vector> using namespace std; const int mod=1e9+7; const int MAX=5e7+10; int arr[MAX]; int n,m,k; int quickSort(int left,int right){//左闭右闭 int temp=arr[left];//存储对照点 int i=left,j=right; while(i<j){//从右边开始找一个小于对照点的数 while(arr[j]>=temp&&i<j){ j--; } //从左边开始找一个大于对照点的数 while(arr[i]<=temp&&i<j){ i++; } //找到后交换两个数 if(i<j){ int num=arr[i]; arr[i]=arr[j]; arr[j]=num; } } //退出循环后i=j的位置就是temp的位置 arr[left]=arr[i]; arr[i]=temp; // return i; // quickSort(left,i-1);//递归左边 // quickSort(i+1,right);//递归右边 if(i+1==k){//刚好是第K个 return arr[i]; }else if(i+1>k){//太大了 return quickSort(left,i-1); }else{//太小了 return quickSort(i+1,right); } } int main(){ scanf("%d%d%d",&n,&m,&k); arr[0]=m; for(int i=1;i<=n-1;i++){ arr[i] = 1LL * arr[i - 1] * m % mod; } int ans=quickSort(0,n-1); printf("%d\n",ans); return 0; }