题意:
给你
个数字,然后这些数字两两相乘,共
个数。问你第
个数的大小。
思路:
二分答案。
但是这样复杂度为
。妥妥超时,怎样把
复杂度降下来。
二分判定
我们可以分为两个集合,一个为正的,一个为负的 。
然后将他们排序,在正的集合里遍历二分,负的集合里遍历二分,最后遍历负的集合,对正的集合遍历二分。
这样二分答案
,判定
,总共复杂度
const ll N = 2e5 + 10;
const ll mod = 1e9;
const ll Max_n = 1e6 + 10;
using namespace std;
vector<ll> q,p;
bool ok(ll x,ll n,ll k){
ll ans = 0;
sort(q.begin(),q.end(),greater<ll>());
sort(p.begin(),p.end());
int s1 = q.size(),s2 = p.size();
for(int i = 0;i < s1;++i){
int l = i,r = s1-1;
while(l < r){
int mid = l + r +1 >>1;
if(q[i]*q[mid] <= x) l = mid;
else r = mid - 1;
}
if(l > i) ans += l -i ;
}
for(int i = 0;i < s2;++i){
int l = i,r = s2 - 1;
while(l < r){
int mid = l + r + 1 >> 1;
if(p[i]*p[mid] <= x) l = mid;
else r = mid - 1;
}
if(l > i) ans += l - i ;
}
if(ans >= k) return 1;
reverse(q.begin(),q.end());
reverse(p.begin(),p.end());
for(int i = 0;i < s1;++i){
int l = -1,r = s2-1;
while(l < r){
int mid = l + r + 1>>1;
if(q[i] * p[mid] <= x) l = mid;
else r = mid - 1;
}
if(l != -1) ans += l + 1;
}
return ans >= k;
}
int main(){
ll n,k;
scanf("%lld%lld",&n,&k);
for(int i = 1;i <= n;++i){
ll a;
scanf("%lld",&a);
if(a<0) q.push_back(a);
else p.push_back(a);
}
ll l = - mod * mod ,r = mod *mod;
while(l < r){
ll mid = l + r >>1;
if(ok(mid,n,k)) r = mid;
else l = mid + 1;
}
cout << r;
}