Problem:
Score: 400 points

Problem Statement

We have N integers A_1, A_2, ..., A_N.

There are \frac{N(N-1)}{2} ways to choose two of them and form a pair. If we compute the product of each of those pairs and sort the results in ascending order, what will be the K-th number in that list?

Constraints

All values in input are integers.

2 \leq N \leq 2 \times 10^5

1 \leq K \leq \frac{N(N-1)}{2}

-10^9 \leq A_i \leq 10^9\ (1 \leq i \leq N)

Input

Input is given from Standard Input in the following format:

N K
A_1 A_2 \dots A_N

Output

Print the answer.

Sample Input 1

4 3
3 3 -4 -2

Sample Output 1

-6

There are six ways to form a pair. The products of those pairs are 9, -12, -6, -12, -6, 8.

Sorting those numbers in ascending order, we have -12, -12, -6, -6, 8, 9. The third number in this list is -6.

Sample Input 2

10 40
5 4 3 2 -1 0 0 0 0 0

Sample Output 2

6

Sample Input 3

30 413
-170202098 -268409015 537203564 983211703 21608710 -443999067 -937727165 -97596546 -372334013 398994917 -972141167 798607104 -949068442 -959948616 37909651 0 886627544 -20098238 0 -948955241 0 -214720580 277222296 -18897162 834475626 0 -425610555 110117526 663621752 0

Sample Output 3

448283280358331064

Solution in Java8 (OpenJDK 1.8.0) (judge verdict: Wrong Answer)


import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.Scanner;

public class Main {
	static int bsearch(List<Long> ps , long x){
		if(ps.isEmpty()){
			return 0;
		}
		if(ps.get(0) >= x){
			return 0;
		}
		if(ps.get(ps.size() - 1) < x){
			return ps.size();
		}
		int left = 0;
		int right = ps.size() - 1;
		while(right - left > 1){
			int mid = (left + right) / 2;
			long v = ps.get(mid);
			if(v < x){
				left = mid;
			}else{
				right = mid;
			}
		}
		return right;
	}
	// x 以下の数値が何個あるか計算する (xはマイナスとする)
	static long f(List<Long> negs , List<Long> poss , long x){
		long ret = 0;
		for(long n : negs){ //n -3  x -81
			long m = (- x + (- n - 1)) /(- n);
			// x以下となるのは m が 26以上のとき
			int cnt = bsearch(poss, m);
			ret += poss.size() - cnt;
		}
		return ret;
	}
	static long g(List<Long> poss , long x){
		long ret = 0;
		int N = poss.size();
		for(int i = 0 ; i < poss.size() - 1; ++i){
			long pi = poss.get(i);
			long m = x / pi;
			int left = i + 1;
			int right = N - 1;
			if(poss.get(left) > m){
				continue;
			}
			if(poss.get(right) <= m){
				ret += N - i - 1;
				continue;
			}
			while(right - left > 1){
				int mid = (left + right) / 2;
				if(poss.get(mid) <= m){
					left = mid;
				}else{
					right = mid;
				}
			}
			ret += (left) - i;			
		}
		return ret;
	}
	
	static long solve(long A[] , long K){
		List<Long> neg = new ArrayList<Long>();
		List<Long> neg2 = new ArrayList<Long>();
		List<Long> pos = new ArrayList<Long>();
		List<Long> zero = new ArrayList<Long>();
		for(long a : A){
			if(a < 0){
				neg.add(a);
				neg2.add(- a);
			}else if(a == 0){
				zero.add(a);
			}else{
				pos.add(a);
			}			
		}
		Collections.sort(neg);
		Collections.sort(neg2);
		Collections.sort(pos);
		Collections.sort(zero);
		long neg_num = neg.size() * pos.size();
		long zero_num = zero.size() * (pos.size() + neg.size()) + (zero.size() * (zero.size() - 1)) / 2;
		if(K > neg_num && K <= neg_num + zero_num){
			return 0;
		}else{
			if(K <= neg_num){
				long left = - (1000000000L * 1000000000L) - 1;
				long right = 0;
				while(right - left > 1){
					long mid = (left + right) / 2;
					long f = f(neg, pos , mid);
					if(K <= f){
						right = mid;
					}else{
						left = mid;
					}
				}
				return right;
			}else{
				long left = 0;
				long right = (1000000000L * 1000000000L) + 1;
				while(right - left > 1){
					long mid = (left + right) / 2;
					long f = g(neg2, mid) + g(pos , mid) + neg_num + zero_num;
					if(K <= f){
						right = mid;
					}else{
						left = mid;
					}
				}
				return right;
			}
		}
	}
	static long solveNaive(long A[] , int K){
		List<Long> lst = new ArrayList<Long>();
		int N = A.length;
		for(int i = 0 ; i < N ; ++i){
			for(int j = i +1 ; j < N ; ++j){
				lst.add(A[i] * A[j]);
			}
		}
		Collections.sort(lst);
		return lst.get(K - 1);
	}
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int N = sc.nextInt();
		long K = sc.nextLong();
		long A[] = new long[N];
		for(int i = 0 ; i < N ; ++i){
			long a = sc.nextLong();
			A[i] = a;
		}
		System.out.println(solve(A, K));
	}
}