UOJ #576. 积的第K小数

【题目描述】:

有两个正整数数列,元素个数分别为N和M。从两个数列中分别任取一个数相乘,这样一共可以得到N×M个数,询问这N×M个数中第K小数是多少。
【输入描述】:

第一行为三个正整数N,M和K。

第二行为N个正整数,表示第一个数列。

第三行为M个正整数,表述第二个数列。
【输出描述】:

一个正整数表示第K小数。
【样例输入1】:

2 3 4
1 2
2 1 3

【样例输出1】:

3

【样例输入2】:

5 5 18
7 2 3 5 8
3 1 3 2 5

【样例输出2】:

16

【时间限制、数据范围及描述】:

时间:1s 空间:128M
编号__ 	N______ 	M_________ 	K______________ 	元素大小(≤)
1 	20 	20 	150 	10^4
2 	50 	50 	2000 	10^4
3 	100 	80 	5000 	10^9
4 	200 	200 	26000 	10^9
5 	10000 	10000 	50050000 	10^4
6 	1000 	20000 	9500000 	10^4
7 	1000 	20000 	10000500 	10^9
8 	2000 	20000 	190000 	10^9
9 	2000 	20000 	199000 	10^9
10 	20000 	20000 	210005000 	10^4
11 	20000 	20000 	210000 	10^5
12 	20000 	20000 	200000 	10^9
13 	20000 	20000 	220000500 	10^5
14 	20000 	20000 	199000500 	10^9
15 	200000 	200000 	180000 	10^4
16 	200000 	200000 	200000 	10^9
17 	2000 	200000 	100001500 	10^9
18 	200000 	180000 	19550000000 	10^5
19 	200000 	200000 	19900010000 	10^9
20 	200000 	200000 	20000010000 	10^9

本题直接二分一个数,然后在n*m个数中看比这个数小的数的个数是否小于等于k即可.
注意找比这个数小的数时,直接利用排序好的数列的阶梯性质找即可,无需二次二分.

Code:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<ctime>
using namespace std;
const int N=200005;
int n,m;
long long k,a[N],b[N];
long long check(long long mid) {
	long long s=0,top=m;
	for(int i=1;i<=n;i++){
		long long now=mid/a[i];
		while(top>0&&b[top]>now){
			top--;
		}
		s+=top;
	}
	return s;
}
int main(){
	scanf("%d%d%lld",&n,&m,&k);
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i]);
	}
	for(int i=1;i<=m;i++){
		scanf("%lld",&b[i]);
	}
	sort(a+1,a+1+n);
	sort(b+1,b+1+m);
	long long l=a[1]*b[1],r=a[n]*b[m];
	while(l<r) {
		long long mid=(l+r)/2;
		if(check(mid)>=k){
			r=mid;
		}
		else{
			l=mid+1;
		}
	}
	printf("%lld\n",l);
	return 0;
}
posted @ 2019-09-11 00:07  prestige  阅读(169)  评论(0编辑  收藏  举报