查找第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 }

原文地址:https://www.cnblogs.com/romaLzhih/p/12342492.html

时间: 2024-08-01 12:22:12

查找第K大的值的相关文章

POJ 3579 3685(二分-查找第k大的值)

POJ 3579 题意 双重二分搜索:对列数X计算∣Xi – Xj∣组成新数列的中位数 思路 对X排序后,与X_i的差大于mid(也就是某个数大于X_i + mid)的那些数的个数如果小于N / 2的话,说明mid太大了.以此为条件进行第一重二分搜索,第二重二分搜索是对X的搜索,直接用lower_bound实现. #include <iostream> #include <algorithm> #include <cstdio> #include <cmath&g

poj 3685 Matrix(二分搜索之查找第k大的值)

Description Given a N × N matrix A, whose element in the i-th row and j-th column Aij is an number that equals i2 + 100000 × i + j2 - 100000 × j + i × j, you are to find the M-th smallest element in the matrix. Input The first line of input is the nu

poj 3579 Median (二分搜索之查找第k大的值)

Description Given N numbers, X1, X2, ... , XN, let us calculate the difference of every pair of numbers: ∣Xi - Xj∣ (1 ≤ i < j ≤ N). We can get C(N,2) differences through this work, and now your task is to find the median of the differences as quickly

leetcode | Median of Two Sorted Arrays 寻找2个有序数组中第k大的值

问题 Median of Two Sorted Arrays There are two sorted arrays A and B of size m and n respectively. Find the median of the two sorted arrays. The overall run time complexity should be O(log(m + n)). 分析 本题更经典通用的描述方式时: 给定2个有序数组,找出2个数组中所有元素中第k大的元素. 思路1 直观思

POJ 2985 The k-th Largest Group(树状数组 并查集/查找第k大的数)

传送门 The k-th Largest Group Time Limit: 2000MS   Memory Limit: 131072K Total Submissions: 8690   Accepted: 2847 Description Newman likes playing with cats. He possesses lots of cats in his home. Because the number of cats is really huge, Newman wants

求区间第k大的值

#include <iostream> using namespace std; int part(int a[], int i, int j) { int tmp = a[i]; if(i < j) { while(i < j) { while(i<j && a[j]>=tmp) j--; if(i < j) a[i] = a[j]; while(i<j && a[i]<tmp) i++; if(i < j) a

215. Kth Largest Element in an Array找出数组中第k大的值

堆排序做的,没有全部排序,找到第k个就结束 public int findKthLargest(int[] nums, int k) { int num = 0; if (nums.length <= 1) return nums[0]; int heapSize = nums.length; //1.构建最大堆 int half = (heapSize-2)/2; for (int i = half;i >= 0;i--) { adjust(nums,heapSize,i); } while

POJ 3662 Telephone Lines (二分+Dijkstra: 最小化第k大的值)

题意 Farmer John想从电话公司修一些电缆连接到他农场.已知N个电线杆编号为1,2,?N,其中1号已经连接电话公司,N号为农场,有P对电线杆可连接. 现给出P对电线杆距离Ai,Bi,Li表示Ai和Bi可连接,需要长度为Li的电缆. 电话公司赞助FJ K条免费电缆,额外的支出为剩下所需电缆的最大长度.求出最小费用. 思路 设mid为某条线的长度,长于mid的线放到免费额度里,否则自己掏钱.如果存在一个临界值x,使得长于x的电线数量恰好等于K,这个临界值对应的解就是最优解.如何计算长于mid

查找第K大的数

类快排 第一种方法 o(n) #include <bits/stdc++.h> using namespace std; const int N = 1000; int s[N]; int partion(int l,int r) { int tmp = s[l]; int i = l, j = r; while(i < j) { while(i < j && s[j] >= tmp) j--; while(i < j && s[i] &