第K大数-二分原来还可以这样

来源:互联网 发布:网络谩骂是否可以报警 编辑:程序博客网 时间:2024/04/29 01:04

题目:

数组A和数组B,里面都有n个整数。数组C共有n^2个整数,分别是A[0] * B[0],A[0] * B[1] ......A[1] * B[0],A[1] * B[1]......A[n - 1] * B[n - 1](数组A同数组B的组合)。求数组C中第K大的数。
例如:A:1 2 3,B:2 3 4。A与B组合成的C包括2 3 4 4 6 8 6 9 12共9个数。
Input
第1行:2个数N和K,中间用空格分隔。N为数组的长度,K对应第K大的数。(2 <= N <= 50000,1 <= K <= 10^9)第2 - N + 1行:每行2个数,分别是A[i]和B[i]。(1 <= A[i],B[i] <= 10^9)
Output
输出第K大的数。
Input 示例
3 21 22 33 4
Output 示例
9

题目分析:

二分A[0]*B[0] -- mid--  A[N-1]*B[N-1],然后求出小于mid的数,用小于mid的数的个数与N*N-K+1比较,一直到最后二分跳出即为答案。
     之前一直不明白为何能够二分到准确的答案,因为如果求第3大,答案应该是8,但是7是不是也满足情况。实际上这是要看二分什么时候跳出。
 如果你发现有3个>=K的就跳出了,那么肯定不是最终答案。但是如果你到l>r的时候再跳出,二分过程中肯定有一刻指向的是序列中的某个值。
举例:还是找上面例子中第3大
k=3
l=2,r=12 mid = 7
大于=7的有3个,3>=k; 注意这个时候不能跳出而是另l=mid+1=8
l=8,r=12,mid=10
大于=10的只有1个<k,那么r=mid-1=9;
l=8,r=9,mid=8
这个同第一种情况,l=mid+1=9;
l=9,r=9,mid=9
>=9的个数2个<k,那么r=mid-1=8跳出循环(实际上跳出循环肯定是有一个所指即所求)
那么实际l=8 r=9时所指的就是答案。

代码:

//直接计算第K大
#include <iostream>#include <algorithm>using namespace std;const int MAXN = 50002;__int64 a[MAXN],b[MAXN];__int64 N,K;__int64 cnt(__int64 mid){__int64 ret = 0; __int64 j = 0;for (__int64 i = N-1; i >= 0; -- i){while(j<N){if (b[j]*a[i] < mid)++j;elsebreak;}ret += N-j;}return ret;}void binarySearch(){__int64 l = a[0]*b[0];__int64 r = a[N-1]*b[N-1];__int64 ans = 0;while (l <= r){__int64 mid = (l+r)>>1;if (cnt(mid) >= K){ans = mid;l = mid + 1;}elser = mid - 1;}cout << ans << endl;}int main(){while (cin >> N >> K){//K = N*N - K + 1;for (int i = 0; i < N; ++ i){cin >> a[i] >> b[i];}sort(a,a+N);sort(b,b+N);binarySearch();}return 0;}


//计算第N*N-K+1小数,这里转换一下
#include <iostream>#include <algorithm>using namespace std;const int MAXN = 50002;__int64 a[MAXN],b[MAXN];__int64 N,K;__int64 cnt(__int64 mid){__int64 ret = 0; __int64 j = N-1;for (__int64 i = 0; i < N; ++ i){while(j>=0){if (b[j]*a[i] > mid)--j;elsebreak;}ret += j+1;}return ret;}void binarySearch(){__int64 l = a[0]*b[0];__int64 r = a[N-1]*b[N-1];__int64 ans = 0;while (l <= r){__int64 mid = (l+r)>>1;if (cnt(mid) >= K){ans = mid;r = mid - 1;}elsel = mid + 1;}cout << ans << endl;}int main(){while (cin >> N >> K){K = N*N - K + 1;for (int i = 0; i < N; ++ i){cin >> a[i] >> b[i];}sort(a,a+N);sort(b,b+N);binarySearch();}return 0;}


原创粉丝点击