版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Ronaldo7_ZYB/article/details/89288910
题目描述
这里是原题地址:小B的游戏
题目大意就是说:有两个序列,任选两个组成新的数中,求第k大的数。
题解
这道题可以使用优先队列解决,时间复杂度是 。
我们来思考一下正解:
我们发现随着这一个具体数值的增大,比这个数小的数对会越来越多,比这个数大的数对会越来约数;那么我们只要找到这么一个数 ,满足小于或等于这个数的个数 ,且这个数尽可能的小,那么这一个数就是我们最终所求的答案。
接下来证明:满足小于或等于这个数 的个数 , 就是一个合法的数。
- 如果 ,一定是按照题意合法的答案。
- 如果
时,设数
的
值为
,则如图所示:
这就对应了算法二分答案。
在查找的时候,我们使用双指针维护,一个指针从前往后扫,一个指针从后往前扫;对于第一个数列的数 ,我们在第二个序列中找到 满足 ,那个第一个数对中以 为第一个数的贡献就是 。
代码如下:
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const LL N = 5000000;
LL k;
LL n,m;
LL a[N];
LL b[N];
bool check(LL x)
{
LL j = m;
LL cnt = 0;
for (LL i=1;i<=n;++i)
{
while (j>1 && a[i]+b[j]>x) j --;
if (a[i]+b[j] <= x) cnt += j;
}
return cnt < k;
}
int main(void)
{
scanf("%lld %lld %lld",&n,&m,&k);
for (LL i=1;i<=n;++i) scanf("%lld",a+i);
for (LL i=1;i<=m;++i) scanf("%lld",b+i);
sort(a+1,a+n+1);
sort(b+1,b+m+1);
LL l = 2,r = 2e9;
while (l+1 < r)
{
LL mid = l+r>>1;
if (check(mid)) l = mid;
else r = mid;
}
//查找个数<k的最大值
if (check(r)) printf("%lld",r+1);
else printf("%lld",l+1);
return 0;
}