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

思路:

20分:暴力枚举+排序,注意long long

30分:和的第K小数改一下(堆);

满分:二分答案,假想一个由{x|x∈A}和{y|y∈B}(A={a1,a2,a3,a4...an},B={b1,b2,b3,b4...bn},已从小到大排序)组成的乘法表C={x*y|x∈A,y∈B},取中间的积进行二分。

代码:

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

const int N=200010;

long long k;
int n,m,a[N],b[N];

int cmp(const void *p1,const void *p2) {
	return (*(int *)p1)-(*(int *)p2);
}

long long check(long long ans) {
	int i;
	long long s=0,top=m,gtmp;
	for(int i=1; i<=n; i++) {
		gtmp=ans/a[i];
		while(top&&b[top]>gtmp)
			top--;
		s+=top;
	}
	return s;
}

int main () {
	scanf("%d%d%lld",&n,&m,&k);
	for(int i=1; i<=n; i++)
		scanf("%d",&a[i]);
	for(int i=1; i<=m; i++)
		scanf("%d",&b[i]);
	qsort(a+1,n,sizeof(a[0]),cmp);
	qsort(b+1,m,sizeof(b[0]),cmp);
	long long ll=a[1]*(long long)b[1];
	long long rr=a[n]*(long long)b[m],mid;
	while(ll<rr) {
		mid=(ll+rr)/2;
		if(check(mid)>=k)
			rr=mid;
		else
			ll=mid+1;
	}
	printf("%lld\n",ll);
	return 0;
}
扫描二维码关注公众号,回复: 7252405 查看本文章

猜你喜欢

转载自www.cnblogs.com/mysh/p/11503797.html