题目链接
题目描述
数组A和数组B,里面都有n个整数。
数组C共有n^2个整数,分别是:
A[0] * B[0],A[0] * B[1] ...... A[0] * B[n-1]
A[1] * B[0],A[1] * B[1] ...... A[1] * B[n-1]
......
A[n - 1] * B[0],A[n - 1] * B[1] ...... A[n - 1] * B[n - 1]
是数组A同数组B的组合,求数组C中第K大的数。
例如:
A:1 2 3,B:2 3 4。
A与B组合成的C为
A[0] A[1] A[2]
B[0] 2 3 4
B[1] 4 6 8
B[2] 6 9 12
共9个数。
输入输出格式
输入格式:
第1行:2个数N和K,中间用空格分隔。N为数组的长度,K对应第K大的数。
第2 - N + 1行:每行2个数,分别是A[i]和B[i]。
输出格式:
输出第K大的数。
数据范围:
(2 <= N <= 50000,1 <= K <= 10^9)
(1 <= A[i],B[i] <= 10^9)
样例
样例一输入:
3 2
1 2
2 3
3 4
样例一输出:
9
思路
1.二分
将A数组升序排序,不难发现, $ B_{x} ast A_{i} $ 为升序序列
那么首先二分第K大的值为h,然后对于序列 $ B_{x} ast A_{i} $ ,二分其中有多少个数小于h
复杂度 $ Theta left( nlog nlog max left( Aleft[ i
ight] ast Bleft[ i
ight]
ight)
ight) $
还有个小优化
考虑将A,B都升序排序
那么序列 $ B_{x} ast A_{i} $ 和 $ A_{x} ast B_{i} $ 都为升序序列
所以在二分小于h的个数时,第m次二分最大的边界不会超过第m-1次二分的答案
维护边界变量即可
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <queue>
#include <list>
#include <map>
#define ll long long
#define ull unsigned long long
using namespace std;
int n;
ull a[50050],b[50050];
ull p,k;
bool check(ull mid) {
ull sum = 0;
ull l = 0, r = n, tmp;
for(int i = 1; i <= n; i++) {
if(r == 0)break;
while(l <= r) {
ull m = (l + r) >> 1;
if(a[i] * b[m] < mid) {
tmp = m;
l = m + 1;
} else r = m - 1;
}
sum += tmp;
l = 0;
}
return sum <= p-k;
}
int main(int argc, char const *argv[])
{
scanf("%d%llu",&n,&k);
p = (ull)n * n;
for(int i = 1; i <= n; i++) {
scanf("%llu%llu",&a[i],&b[i]);
}
sort(a+1,a+1+n);
sort(b+1,b+1+n);
ull l = a[1]*b[1], r = (ull)a[n]*b[n];
ull ans;
while(l <= r) {
ull mid = (l+r) >> 1;
if(check(mid)) {
ans = mid;
l = mid + 1;
} else r = mid - 1;
}
printf("%llu",ans);
return 0;
}