51nod 1105:第K大的数

基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题
 收藏
 关注
数组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

之前做过的left right都是数组的下标,找数组中的元素。这次是直接给那个数的范围,找数组中的数。

双二分。一开始我是想第k大的数,即是 第n*n-k+1小的数,所以找小的元素,结果前19组test都过了,就第20组一直WA。后来想N最大50000,N*N超过了long long了。这个思路只能被划掉。乖乖找第k大的,记录有多少比mid大的,再去比较。

代码:

<pre name="code" class="cpp">#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
#include <string>
#include <cstring>
#pragma warning(disable:4996)
using namespace std;

long long a[50005], b[50005];
int len, k;

int search(long long y, long long x)
{
	int i, left = 1, right = len;
	long long mid, ans=len;
	while (left <= right)
	{
		mid = left + (right - left) / 2;
		if (a[y] * b[mid] >= x)
		{
			ans = min(ans, mid);
			right = mid - 1;
		}
		else
		{
			left = mid + 1;
		}
	}
	return ans;
}

bool check(long long x)
{
	int i, ans = 0;
	for (i = 1; i <= len; i++)
	{
		if (a[i] * b[len] < x)continue;
		ans += ((len- search(i, x))+1);
	}
	return ans >= k;
}

int main()
{
	int i;
	long long start, end, mid, ans;
	cin >> len >> k;
	for (i = 1; i <= len; i++)
		cin >> a[i] >> b[i];
	
	sort(a + 1, a + len + 1);
	sort(b + 1, b + len + 1);

	start = a[1] * b[1] - 1;
	end = a[len] * b[len] + 1;
	ans = 0;

	while (end - start > 1)
	{
		mid = start + (end - start) / 2;
		if (check(mid))
		{
			ans = max(ans, mid);
			start = mid;
		}
		else
		{
			end = mid;
		}
	}
	cout << ans << endl;

	return 0;
}



    
        

版权声明:本文为博主原创文章,未经博主允许不得转载。

原文地址:https://www.cnblogs.com/lightspeedsmallson/p/4899583.html