upc 4875 第k大数 二分查找

来源:互联网 发布:u盘在mac上不显示文件 编辑:程序博客网 时间:2024/06/11 10:29

4875: 第k大数

时间限制: 10 Sec  内存限制: 128 MB
提交: 74  解决: 22
[提交][状态][讨论版]

题目描述

有两个序列a,b,它们的长度分别为n和m,那么将两个序列中的元素对应相乘后得到的n*m个元素从大到小排列后的第k个元素是什么?

输入

输入的第一行为一个正整数T (T<=10),代表一共有T组测试数据。

每组测试数据的第一行有三个正整数n,m和k(1<=n, m<=100000,1<=k<=n*m),分别代表a序列的长度,b序列的长度,以及所求元素的下标。第二行为n个正整数代表序列a。第三行为m个正整数代表序列b。序列中所有元素的大小满足[1,100000]。

输出

对于每组测试数据,输出一行包含一个整数代表第k大的元素是多少。

样例输入

33 2 31 2 31 22 2 11 11 12 2 41 11 1

样例输出

311
设置两个数组a,b,然后从小到大分别排一下序,
首先思考所求的数一定在a[0]*b[0]--a[n-1]*b[n-1],,设置一个mid等于两端除2,接下来寻找所有的乘出来的数中有多少比mid大的,得出mid是第几大元素,如果mid大于k,说明k在mid右边;否则k在mid左边,
然后在不断二分,直到mid=k为止,在找有多少比mid大的数的时候,设a数组从后往前扫,b数组从前往后扫,如果a[i]*b[j]>=mid,则a[i-1]扫的时候直接从b数组的j开始扫,不用从0,想一下就知道。
#include <iostream>#include <string.h>#include <algorithm>using namespace std;typedef long long ll;ll m,n;ll a[100010];ll b[100010];ll judge(ll mid){    ll sum=0;    ll j=0;    for (int i=n-1;i>=0;i--)     for (;j<=m-1;j++)     {        if (a[i]*b[j]>=mid)        {        sum+=(m-j);        break;         }     }     return sum;}int main(){    ll t,mid;    ll k;    ll ans;    cin>>t;    while (t--)    {        scanf("%lld%lld%lld",&n,&m,&k);        for (int i=0;i<n;i++)        scanf("%lld",&a[i]);        for (int j=0;j<m;j++)        scanf("%lld",&b[j]);        sort(a,a+n);        sort(b,b+m);        ll l=a[0]*b[0];        ll r=a[n-1]*b[m-1];        while (l<=r)        {            mid=(l+r)/2;            int po=judge(mid);            if (po>=k)            {                ans=mid;                l=mid+1;            }            else             r=mid-1;        }        printf("%lld\n",ans);    }}


原创粉丝点击