http://acm.cugb.edu.cn/JudgeOnline/showproblem?problem_id=1220
题意:有两个数组a和b元素个数都有n(10000)个,且均为正整数。。。求a[]*b[]所生成的c[]数组的第k大数。。
分析:二分求一个值v,这个值是最末尾一个c的元素中>=v的个数>=k。。。然后扫描a数组,二分b数组得到>=v的元素个数。。。
其实二分b数组还可以省略。。。因为a和b数组都是排序了的,那么对a中的元素往后扫,b中元素往后扫就可以得到结果了。。。。
二分还是要写死我啊。。。。。
代码:
一个二分。。100+ms。。难得的rank1啊啊啊。。
#include <stdio.h>
#include <algorithm>
#include <cmath>
#include <iostream>
using namespace std;
const int N=10010;
int n, k, a[N], b[N], flag;
int cal(int num)
{
int i, j, k, ans, tmp;
if(a[n-1]*b[n-1]<=num)
return 0;
j = n-1;
ans = 0;
for(i=0; i<n; i++)
{
for(; j>=0 && a[i]*b[j]>num; j--);
ans += n-1-j;
}
return ans;
}
int bs()
{
int i, l, r, mid, ans, tmp;
l=1, r=a[n-1]*b[n-1];
while(l<=r)
{
flag = 0;
mid = (l+r)>>1;
tmp = cal(mid);
if(tmp>=k)
l = mid+1;
else
r = mid-1;
}
//r为最后一个满足比r大的个数>=k的值,所以r+1即为所求。。。
return r+1;
}
int main()
{
int i, j, cas;
scanf("%d", &cas);
while(cas--)
{
scanf("%d%d", &n, &k);
for(i=0; i<n; i++)
scanf("%d", &a[i]);
for(i=0; i<n; i++)
scanf("%d", &b[i]);
sort(a, a+n);
sort(b, b+n);
printf("%d\n", bs());
}
return 0;
}
两个二分。。300+ms
#include <stdio.h>
#include <algorithm>
#include <cmath>
#include <iostream>
using namespace std;
const int N=10010;
int n, k, a[N], b[N], flag;
int bs1(int i, int num) //统计和a[i]相乘>num的总个数
{
int l, r, mid;
l=0, r=n-1;
while(l<=r)
{
mid = (l+r)>>1;
if(a[i]*b[mid]<=num)
l = mid+1;
else
r = mid-1;
}
//r为乘积<=num的最后一个位置
return n-1-r; //乘积>num的总个数
}
int bs()
{
int i, l, r, mid, ans, tmp;
l=1, r=a[n-1]*b[n-1];
while(l<=r)
{
flag = 0;
mid = (l+r)>>1;
tmp = 0;
for(i=0; i<n; i++) //对a扫描,二分b
tmp += bs1(i, mid);
if(tmp>=k)
l = mid+1;
else
r = mid-1;
}
//r为最后一个满足比r大的个数>=k的值,所以r+1即为所求。。。
return r+1;
}
int main()
{
int i, j, cas;
scanf("%d", &cas);
while(cas--)
{
scanf("%d%d", &n, &k);
for(i=0; i<n; i++)
scanf("%d", &a[i]);
for(i=0; i<n; i++)
scanf("%d", &b[i]);
sort(a, a+n);
sort(b, b+n);
printf("%d\n", bs());
}
return 0;
}