数组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和b进行排序,我们要求解的值肯定是位于a[0]*b[0]和a[n-1]*b[n-1]之间的,我们可以二分枚举这个值,然后求解a和b数组中元素的乘积大于等于这个数的个数,如果ans>=k,则l=mid+1,否则r=mid-1.剩下的问题便是求解a和b数组元素的乘积中大于等于某一个值的个数,我们可以采用枚举a数组中的每一个元素,然后二分查找到那个位置pos,则ans+=n-pos,总之就是双二分。
#include <cmath> #include <cstdio> #include <cstdlib> #include <cstring> #include <iostream> #include <string> #include <vector> #include <deque> #include <queue> #include <stack> #include <map> #include <set> #include <utility> #include <algorithm> #include <functional> using namespace std; typedef long long ll; const int maxn = 50010; ll a[maxn], b[maxn]; int n, k; int bsearch(ll x, ll y) { int l = 0, r = n - 1, mid; int ans = n; while(l <= r) { mid = l + (r - l) / 2; if(x*b[mid] >= y) { ans = min(ans, mid); r = mid - 1; } else { l = mid + 1; } } return ans; } bool check(ll x) { ll ans = 0; for(int i = 0; i < n; ++i) { if(a[i]*b[n-1] < x) continue; ans += n - bsearch(a[i], x); } return ans >= k; } int main() { //freopen("aa.in", "r", stdin); ll ans, l, r, mid; scanf("%d %d", &n, &k); for(int i = 0; i < n; ++i) { scanf("%lld %lld", &a[i], &b[i]); } sort(a, a + n); sort(b, b + n); ans = a[0] * b[0]; l = a[0] * b[0]; r = a[n-1] * b[n-1]; while(l <= r) { mid = l + (r - l) / 2; if(check(mid)) { ans = max(ans, mid); l = mid + 1; } else { r = mid - 1; } } printf("%lld\n", ans); return 0; }