查找第K大的值

这种题一般是给定N个数,然后N个数之间通过某种计算得到了新的数列,求这新的数列的第K大的值


POJ3579

题意:

用$N$个数的序列$x[i]$,生成一个新序列$b$。

新的序列定义为:对于任意的$ i$,$j$且 $i != j $有$b[] = abs(x[i] - x[j])$

问新序列的中位数是什么,如果新序列的长度为偶数那么我们定义中位数为排序后第len/2位置的那个数

解法:

相当于问新序列中的第K大的数多少。

注意新数列不可能全都算出来。

二分答案,二分那个第K大的数的值。

$x[i]-x[j] \ge mid$

相当于

$x[i] \ge mid+x[j]$

然后我们在排序过的原数组中,对每个$a[i]$二分这个$mid$值,统计有多少个值小于它,统计累加所有的值,最后看是不是小于K

代码如下:

 1 int N;
 2 int a[MAXN];
 3 LL M;
 4 
 5 bool C(int t) {
 6     LL cnt = 0;
 7     for (int i = 0; i < N; i++) {
 8         cnt += N - (lower_bound(a + i + 1, a + N, a[i] + t) - a);
 9     }
10     return cnt <= M / 2;
11 }
12 
13 void solve() {
14     sort(a, a + N);
15     M = N * (N - 1) / 2;
16     int ub = a[N - 1] + 1, lb = 0;
17     while (ub - lb > 1) {
18         int mid = (ub + lb) >> 1;
19         if (C(mid)) {
20             ub = mid;
21         } else {
22             lb = mid;
23         }
24     }
25     cout << lb << endl;
26     return;
27 }
28 
29 int main() {
30 #ifndef ONLINE_JUDGE
31     freopen("input.txt", "r", stdin);
32 #endif  // !ONLINE_JUDGE
33     while (~scanf("%d", &N)) {
34         for (int i = 0; i < N; i++) {
35             scanf("%d", &a[i]);
36         }
37         solve();
38     }
39     return 0;
40 }

猜你喜欢

转载自www.cnblogs.com/romaLzhih/p/12342492.html
今日推荐