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; }
时间: 2024-10-08 14:54:05