您的位置:首页 > 其它

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

2013-11-06 22:30 489 查看

题目:

数组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 2
1 2
2 3
3 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;
else
break;
}
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;
}
else
r = 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;
else
break;
}
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;
}
else
l = 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: