分别考虑原数组 a[]a[]a[] 中所有的正数,负数以及 0 的数量:
设 a[]a[]a[] 中正数的数量为 cnt1cnt1cnt1 个,把 a[]a[]a[] 中所有正数保存在 bz[]bz[]bz[] 数组中,
负数数量为 cnt2cnt2cnt2 个,保存在 bf[]bf[]bf[] 数组中,
0 的数量为 cnt0cnt0cnt0 个。
设 x1x1x1, x0x0x0, x2x2x2 分别为两两相乘之后新生成的 bbb 序列中所有正数,0 ,负数的个数,则:
x1=cnt1∗(cnt1−1)/2+cnt2∗(cnt2−1)/2x1=cnt1*(cnt1-1)/2+cnt2*(cnt2-1)/2x1=cnt1∗(cnt1−1)/2+cnt2∗(cnt2−1)/2
x0=cnt0∗(n−1)x0=cnt0*(n-1)x0=cnt0∗(n−1)
x2=cnt1∗cnt2x2=cnt1*cnt2x2=cnt1∗cnt2
讨论 t 的大小:
- 若 t≤x1t≤x1t≤x1 ,则这个第 ttt 大数一定是在 bbb 序列中所有的正数中产生的,
把 bz[]bz[]bz[] 数组升序排序,bf[]bf[]bf[] 数组先全部变为正数 ( 两两相乘之后一定为正数,先把每个数变成正数方便计算),然后升序排序。
二分答案找到 bz[]bz[]bz[] 所有数字和 bf[]bf[]bf[] 数组中所有数字两两相乘之后的第 ttt 大。
-
若 x1<t≤x1+x0x1<t≤x1+x0x1<t≤x1+x0,则这个第 ttt 大数就是 0 。
-
若 t>x1+x0t>x1+x0t>x1+x0 则这个第 ttt 大数一定是在 x2x2x2 个负数中产生的,
问题转化为找到 bz[]bz[]bz[] 数组中所有数字和 bf[]bf[]bf[] 数组中所有数字两两相乘后的第 t−(x1+x0)t-(x1+x0)t−(x1+x0) 大
同样通过二分答案找到这个第 t−(x1+x0)t-(x1+x0)t−(x1+x0) 大数字, 即是原问题所有数字中的第 ttt 大。
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 1e7+10;
ll bz[maxn]= {0}, bf[maxn]= {0};
ll x=0, n=0, t=0;
ll cnt1=0, cnt0=0, cnt2=0;
ll x1=0, x0=0, x2=0;
ll l=0 , r=0;
namespace IO_ReadWrite {
#define getchar()(p1==p2&&(p2=(p1=_buf)+fread(_buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char _buf[1<<21],*p1=_buf,*p2=_buf;
char ch;bool ff;
template <typename T>
inline void read(T &x){
x=0;ff=false;ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')ff=true;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
if(ff)x=~x+1;
return;
}
template <typename T>
inline void write(T x){
if(x<0)putchar('-'),x=~x+1;
if(x>9)write(x/10);
putchar(x%10+'0');
return;
}
inline void ReadChar(char &c){
do{c=getchar();}while(ch<'0'||ch>'9');return;
}
template <typename T>
inline void writeln(T x){write(x);putchar('\n');return;}
}
using namespace IO_ReadWrite;
bool judge(ll num) {
ll tmp = 0;
for (int i = 0; i < cnt1; i++) {
ll p = upper_bound(bz, bz+cnt1, num/bz[i])-bz;
if (p > i) tmp += cnt1-p;
else tmp += cnt1-i-1;
}
for (int i = 0; i < cnt2; i++) {
ll p = upper_bound(bf, bf+cnt2, num/bf[i])-bf;
if (p > i) tmp += cnt2-p;
else tmp += cnt2-i-1;
}
return tmp >= t;
}
bool check(ll num) {
ll tmp = 0;
for (int i = 0; i < cnt1; i++) {
tmp += cnt2-(upper_bound(bf,bf+cnt2, floor((double)num/bz[i]))-bf);
}
return tmp >= t-(x1+x0);
}
int main() {
read(n);read(t);
for (int i = 0; i < n; i++) {
read(x);
if (x > 0) bz[cnt1++] = x;
else if (x == 0) cnt0 ++;
else bf[cnt2++] = x;
}
x1 = cnt1*(cnt1-1)/2+cnt2*(cnt2-1)/2;
x0 = cnt0*(n-1);x2 = cnt1*cnt2;
if (t <= x1) {
for(int i=0; i<cnt2; i++)bf[i]*=-1;
sort(bz,bz+cnt1);
sort(bf,bf+cnt2);
l = min(bz[0]*bz[1], bf[0]*bf[1]);
r = max(bz[cnt1-1]*bz[cnt1-2], bf[cnt2-1]*bf[cnt2-2]);
while (l <= r) {
ll mid = (l+r)>>1;
if (judge(mid))l = mid+1;
else r = mid-1;
}
writeln(l);
}
else if (t > x1 && t <= x1+x0)putchar('0');
else {
sort(bz, bz+cnt1);
sort(bf, bf+cnt2);
l = bz[0]*bf[0];
r = bz[cnt1-1]*bf[cnt2-1];
while (l <= r) {
ll mid = (l+r)/2;
if (check(mid))l = mid+1;
else r = mid-1;
}
writeln(l);
}
return 0;
}