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; }