俗话说二分很难,真的很难,,,很难。(我会说这道题解一晚上么)
题目让求两数列乘积的n*m个数中第k大。
思路就是在[min,max]的范围内二分答案,然后对于每个二分的中点mid,枚举a[i],二分求出对于每个a[i],有几个b[j]使得a[i]*b[j]>=mid。然后把统计的个数全都加起来就是mid在n*m个数中的排名。
我们要找的就是最大的mid使得n*m个数中大于等于mid的数共有k个。
#pragma warning(disable:4996)
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
int n, m;
LL k;
int a[100005], b[100005];
int find(int target, LL midd){//返回左数第一个b[i]使得b[i]*target>=midd的角标i
int low = 1, high = m;
while (low + 1 < high){
int mid = (low + high) >> 1;
if ((LL)b[mid] * target < midd)low = mid + 1;
else high = mid;
}
if ((LL)b[low] * target >= midd)return low;
if ((LL)b[high] * target >= midd)return high;
return m + 1;
}
int main(){
//freopen("in.txt", "r", stdin);
while (~scanf("%d", &n)){
scanf("%d %lld", &m, &k);
for (int i = 1; i <= n; i++)scanf("%d", a + i);
for (int j = 1; j <= m; j++)scanf("%d", b + j);
sort(a + 1, a + 1 + n);
sort(b + 1, b + 1 + m);
LL low = (LL)a[1] * b[1], high = (LL)a[n] * b[m];
while (low + 1< high){
LL mid = (low + high) >> 1;
LL rank = 0;
for (int i = 1; i <= n; i++){
int index = find(a[i], mid);
rank += m + 1 - index;
}
//rank是n*m个数中>=mid的个数
if (rank < k)high = mid - 1;
else if (rank>k)low = mid + 1;
else low = mid;
}
LL ans = -1;
for (int i = 1; i <= n; i++){
int u = find(a[i], low);
int v = find(a[i], high);
if (low%a[i] == 0 && u <= m&&b[u] * (LL)a[i] == low){
ans = low;
break;
}
if (high%a[i] == 0 && v <= m&&b[v] * (LL)a[i] == high){
ans = high;
break;
}
}
printf("%lld\n", ans);
}
return 0;
}