两序列相乘的第k大元素

来源:互联网 发布:全知叙述视角范文 编辑:程序博客网 时间:2024/06/11 07:38

4875: 第k大数

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

题目描述

有两个序列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

【分析】:直接求解很明显数据量太大。

二分枚举。

相乘后的新序列的最大值和最小值很容易得出,然后对这个区间进行二分枚举。

有点像猜数。

对每次猜的数x,求一下有多少个数比x大,直到猜的数恰好有k个数比x大,计算结束。


如何求比x大的数有多少个:

序列a,b都按从大到小排序

设两个下标i=0,j=m-1分别跑a和b;

看代码中的函数 f( ll x ) 就能看懂。

【代码】:

#include<bits/stdc++.h>using namespace std;typedef long long ll;int n,m,k,T;ll a[101010],b[101010];bool cmp(ll c,ll d){    return c>d;}ll f(ll x)//统计>=x的数量{    ll c=0,j=m-1;    for(int i=0;i<n;i++)    {        while(j&&a[i]*b[j]<x)j--;        if(a[i]*b[j]>=x)c+=j+1;    }    return c;}int main(){    cin>>T;    while(T--)    {        cin>>n>>m>>k;        for(int i=0;i<n;i++) scanf("%lld",&a[i]);        for(int i=0;i<m;i++) scanf("%lld",&b[i]);        sort(a,a+n,cmp);        sort(b,b+m,cmp);        ll mid,r=a[0]*b[0],l=a[n-1]*b[m-1];        while(l<r)        {            mid=(l+r)/2;            if(f(mid)>=k)                l=mid+1;            else r=mid;        }        if(f(l)<k)l--;//测试发现有时少1,干脆特判了一下...        cout<<l<<endl;    }}/**************************************************************    Problem: 4875    User: summer17083    Language: C++    Result: 正确    Time:1192 ms    Memory:3280 kb****************************************************************/