1540 第k大数

1540: 第k大数

Time Limit: 10 Sec   Memory Limit: 128 MB
Submit: 573   Solved: 73
[ Submit][ Status][ Web Board]

Description

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

Input

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

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

Output

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

Sample Input

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

Sample Output

311

HINT

Source

[ Submit][ Status][ Web Board]


具体解析,看下代码

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <string>
#define ll long long

using namespace std;
const int maxn=1000000+5;

ll a[maxn],b[maxn];
ll t,n,m,k;

bool cmp(int A,int B){
    return A > B;
}

ll jdg(ll mid){

    ll cnt=0;
    ll j=1;
    for(ll i=n;i>=1;i--){
        /*
            这里也很细节,对a数组从最大的开始,对b数组从最小的开始,如果a*b里面某个比较小的了,
            那么a[i]后面的那个题,肯定乘以比当前b[j]大的数,然后就优化出来了。
        */
        while(j <=m){
            if(a[i]*b[j] >= mid){
                cnt+=m-j+1;
                break ;
            }
            else{
                j++;
            }
        }
    }

    return cnt;
}

int main(){

    scanf("%lld",&t);
    while(t--){
        scanf("%lld%lld%lld",&n,&m,&k);
        for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
        for(int j=1;j<=m;j++) scanf("%lld",&b[j]);

        sort(a+1,a+1+n);
        sort(b+1,b+1+m);

        ll mid,left,right;

        left=a[1]*b[1];/*最小值*/
        right=a[n]*b[m];/*最大值*/
        ll ans;
        while(left <= right){
            mid=(left+right)/2;
            /*这里可以是一点点逼近吧*/
            ll ce=jdg(mid);

            if(ce >= k){
                ans=mid;
                left=mid+1;
            }
            else{
                right=mid-1;
            }
        }
        printf("%lld\n",ans);

    }


    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值