查找第K大的值
Posted romalzhih
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了查找第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 }
POJ3685
题意:
有一个$ N*N$ 的矩阵$ A$ ,$A[i][j]=i^2+100000i+j^2-100000j+ij$
求所有矩阵元素中第$ K$ 大的值
解法:
求第$ K$ 大的值,二分答案
首先肯定是二分这个K值是多少,接下来就是验证的问题。
由于$ N*N$ 的值很大,所以我们必须找到它的单调性,那么有以下式子:
$A[i+1][j] = A[i][j] + (2*i + j + 1 + 100000)$(同一列递推式)
$A[i][j+1] = A[i][j] + (2*j + i + 1 - 100000)$ (同一行递推式)
可以发现:在列方向上,矩阵单调递增,而在行方向上上,当$ (2*j + i + 1)> 100000 $ 时,递增,反之递减。
那么我们在每个列方向上直接二分那个$ i$ 值的大小,判断的一句就是$ A[i][j]$ 与假想$ K$ 值的大小关系。
代码如下:
1 LL N, M; 2 3 LL cal(LL i, LL j) { return i * i + 100000 * i + j * j - 100000 * j + i * j; } 4 5 bool C(LL x) { 6 LL sum = 0; 7 for (int j = 1; j <= N; j++) { 8 LL ub = N + 1, lb = 0; 9 LL ans = 0; 10 while (ub - lb > 1) { 11 LL mid = (ub + lb) >> 1; 12 if (cal(mid, j) <= x) { 13 ans = mid; 14 lb = mid; 15 } else { 16 ub = mid; 17 } 18 } 19 sum += ans; 20 } 21 return sum >= M; 22 } 23 24 void solve() { 25 LL ub = LLINF, lb = -LLINF; 26 while (ub - lb > 1) { 27 LL mid = (ub + lb) >> 1; 28 if (C(mid)) { 29 ub = mid; 30 } else { 31 lb = mid; 32 } 33 } 34 cout << ub << endl; 35 return; 36 } 37 38 int main() { 39 #ifndef ONLINE_JUDGE 40 freopen("input.txt", "r", stdin); 41 #endif // !ONLINE_JUDGE 42 int T = READ(); 43 while (T--) { 44 getchar(); 45 scanf("%lld%lld", &N, &M); 46 solve(); 47 } 48 return 0; 49 }
以上是关于查找第K大的值的主要内容,如果未能解决你的问题,请参考以下文章