兩序列相乘的第k大元素
阿新 • • 發佈:2019-01-06
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 ****************************************************************/