2015 年 JXNU_ACS 算法组寒假第一次周赛 1003 第K小的数

第K小的数


Problem Description

现有数组A和B,接下来进行如下操作。
对于A中的每一个数,它都要与B中的每一个数分别相加且只加一次,相加的结果分别存入数组C中。
也就是说,A和B中的元素两两相加可以得到数组C。
例如A为[2,3],B为[4,5].那么由A和B中的元素两两相加得到的数组C为[6,7,7,8],显然C的数的长度等于A的长度乘以B的长度。
现在给你数组A和B,求由A和B两两相加得到的数组C中,第K小的数字。

Input

输入的第一行为正整数t代表有t组测试数据。
对于每组测试数据,输入的第一行为三个整数a,b, K:a,b代表将要输入数组A和B的长度。
紧接着两行, 分别有a和b个数, 代表数组A和B中的元素。数组元素范围是[0,2^31-1],a,b的范围是[1,10^5], K的范围是[1,a*b]。

Output

对应每组测试数据,
输出由A和B中元素两两相加得到的数组c中第K小的数字。每个数字占一行。

Sample Input

2
2 2 3
1 2
3 4
3 3 4
1 2 7
3 4 5

Sample Output

5
6

Author

JXNU_WY 


显然直接枚举K的话时间复杂度为O(n*m),n*m高达10^10铁定会超时
考虑用二分的方法在 [a[1]+b[1],a[n]+b[m]]的区间二分枚举答案k ,  时间复杂度log(10^9)
这是二分答案,是第一次二分,然后利用二分法快速统计在有序数组里某个数的排名。
故而在judge()函数中也要用二分查找的方式计算小于等于k的数字个数有几个 复杂度n*log(m)。
故总复杂度为n*log(m)*log(10^9)即复杂度最大为10^5*log(10^5)*log(10^9)=2.3*10^7
故此复杂度足以在时限内解决问题。
下面是C++的参考代码
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<sstream>
#include<vector>
#include<map>
#include<stack>
#include<list>
#include<set>
#include<queue>
#define LL long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1 | 1
using namespace std;
const int maxn=100005;
LL n,m,k;
LL a[maxn],b[maxn];
bool judge(LL mid)
{
    LL cnt=0;
    //printf("mid = %d\n",mid);
    for(int i=0;i<n;i++)
    {
        if(mid<a[i]) break;
        LL v=mid-a[i];
        cnt+=upper_bound(b,b+m,v)-b;
    }
    return cnt<k;
}
int main()
{
    int t;
    cin.sync_with_stdio(false);
    cin>>t;
    while(t--)
    {
        cin>>n>>m>>k;
        for(int i=0;i<n;i++) cin>>a[i];
        for(int i=0;i<m;i++) cin>>b[i];
        sort(a,a+n);sort(b,b+m);
        LL l=a[0]+b[0],r=a[n-1]+b[m-1];
        while(l<r)
        {
            LL mid=(l+r)>>1;
            if(judge(mid)) l=mid+1;
            else r=mid;
        }
        cout<<l<<endl;
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值