http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1105
题意a序列和b序列,ab序列是 a和b两两组合,问你ab中第k大是多少。。
这题是个二分套二分,是个二分好题。。为什么好呢,因为这个二分容易写残疾啊。。。(总之就是我太弱了
接下来分析一下这个题的解法和要注意的地方。
一个显然的方法就是二分答案了,然后判断mid是第几大就可以了。。
但是,仔细一想?咦。。会不会二分的答案其实不是ab数组里面的呢?会不会ab里面有很多个一样的值我无法返回正确答案呢?
我们先分析二分时候我们计算的是什么。。
我们计算的mid在ab数组里面时候,枚举a,二分b就可以知道有几个大于等于mid了,
在设计二分的时候-当返回值大于等于k的时候,使得l=mid+1;(参考blog--《你真的会二分查找吗?》)
我们这时候考虑一下我们会遇到的问题,
Q计算的时候会不会有什么问题?例如mid不是ab数组里面的一个数。
A我们先不考虑是不是ab数组里的一个数,我们计算的是比mid大的ab中的数有多少个。
Q 如果一个数是第k大但是这个数有很多呢?
A (参考blog--《你真的会二分查找吗?》),这里返回第一个大于等于它的值。
Q 会不会返回一个不在ab数组里的一个数呢?
A答案是不会的,因为这个问题可以划归到上一个问题,既然返回的是第一个大于等于它的值,那么如果mid不合法,那么一定存在一个和mid计算值一样的,并且这个合法值要小于mid,(因为不存在的时候要向上取整的,自然虽然计算值一样但是存在的较小)。。
PS。。很多地方可能说的不对,望大家指正。
放代码:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn=50000;
long long n,k;
long long A[maxn],B[maxn];
long long Ca(long long x){
long long f;
long long ret1=0;
for(int i=0;i<n;i++){
f=x/A[i];
if(x%A[i]!=0)
f++;
if(B[n-1]>=f)
ret1+=(n-(long long)(lower_bound(B,B+n,f)-B));
}
return ret1;
}
int main()
{
cin>>n>>k;
for(int i=0;i<n;i++){
cin>>A[i]>>B[i];
}
sort(A,A+n);
sort(B,B+n);
long long l=A[0]*B[0],r=A[n-1]*B[n-1],mid;
while(l<=r){
mid=(l+r)/2;
long long x=Ca(mid);
if(x>=k){
l=mid+1;
}
else{
r=mid-1;
}
}
cout<<l-1<<endl;
return 0;
}