目标用 O ( n ) O(n) O(n)时间找到 k t h kth kth
原题是
N
O
I
p
2008
NOIp2008
NOIp2008提高组的完形
用类似快排的思想,对于一段区间的数,每次选择一个点
t
m
p
tmp
tmp为枢轴点
需要保证排好以后,
t
m
p
tmp
tmp左边的数都比它小,右边的数都比它大
然后看看目标
k
k
k在左区间还是右区间,继续具体排序
对于
t
m
p
tmp
tmp的选择可以用随机数,也可以用
l
+
r
>
>
1
l+r>>1
l+r>>1,实测后者其实更快
理论上复杂度是
O
(
n
)
O(n)
O(n)的,但是其实要慢一点
Code:
//#pragma GCC optmize("-Ofast")
#include <bits/stdc++.h>
#define maxn 10000010
using namespace std;
int n, m, a[maxn];
inline int read(){
int s = 0, w = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
return s * w;
}
int find(int l, int r){
int tmp = (r + l) >> 1, value = a[tmp], i = l, j = r;
swap(a[l], a[tmp]);
while (i < j){
while (i < j && a[j] > value) --j;
if (i < j) a[i++] = a[j];
while (i < j && a[i] < value) ++i;
if (i < j) a[j--] = a[i];
}
a[i] = value;
if (i < m) return find(i, r);
else if (i > m) return find(l, i - 1);
else return i;
}
int main(){
freopen("1.txt", "r", stdin);
freopen("test1.txt", "w", stdout);
srand(time(0));
n = read(), m = read();
for (int i = 1; i <= n; ++i) a[i] = read();
printf("%d\n", a[find(1, n)]);
return 0;
}