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 C# (.NET Core 3.1.201) (judge verdict: Accepted)

using System;
using System.Linq;
using System.Collections.Generic;
using static System.Console;
using System.Text;
using System.IO;
using static System.Math;
using System.Numerics;

namespace AtCoder
{
    class Program
    {
        static public long[] Sarray() { return ReadLine().Split().Select(long.Parse).ToArray(); }
        static public List<long> Slist() { return ReadLine().Split().Select(long.Parse).ToList(); }
        static public (T1 a, T2 b) Slice<T1, T2>()
        {
            var t = ReadLine().Split();
            return (
            (T1)Convert.ChangeType(t[0], typeof(T1)),
            (T2)Convert.ChangeType(t[1], typeof(T2)));
        }
        static long Mod = (long)1e9 + 7;
        static void Main(string[] args)
        {
            SetOut(new StreamWriter(OpenStandardOutput()) { AutoFlush = false });
            Solve();
            Out.Flush();
            Read();
        }
        static void Solve()
        {
            (long N, long K) = Slice<long, long>();
            var Ai = Sarray();
            var Am = Ai.Where(a => a < 0).Select(a => -a).ToList();
            var Ap = Ai.Where(a => 0 <= a).ToList();
            Am.Sort();
            Ap.Sort();
            var mNum = (long)Am.Count * Ap.Count;
            var lb = new lb<long>();
            if (mNum < K)//プラスになるものでサーチ Am,AmとAp,Ap
            {
                bool IsOk(long n, long k)
                {//n未満になる組み合わせがk未満ならok
                    var cnt = 0L;
                    for (var i = 0; i < Am.Count; ++i)
                    {
                        if (n == 0) continue;//0未満になるものはない
                        if (Am[i] == 0)//0の場合は全部
                        {
                            cnt += Am.Count - (i + 1);
                            continue;
                        }
                        var s = (n + Am[i] - 1) / Am[i];//かけ合わせたらn以上になるもの
                        var ab = ~Am.BinarySearch(s, lb);
                        ab = Max(0, ab - (i + 1));
                        cnt += ab;
                    }
                    for (var i = 0; i < Ap.Count; ++i)
                    {
                        if (n == 0) continue;
                        if (Ap[i] == 0)
                        {
                            cnt += Ap.Count - (i + 1);
                            continue;
                        }
                        var s = (n + Ap[i] - 1) / Ap[i];
                        var ab = ~Ap.BinarySearch(s, lb);
                        ab = Max(0, ab - (i + 1));
                        cnt += ab;
                    }
                    return cnt < k;
                };
                WriteLine(bSearch(0, (long)1e18 + 1, K - mNum, IsOk));
            }
            else//マイナスになるものでサーチAm,Ap
            {
                bool IsOk(long n, long k)
                {
                    var cnt = 0L;
                    for (var i = 0; i < Am.Count; ++i)
                    {
                        if (n == 0) continue;
                        if (Am[i] == 0)
                        {
                            cnt += Ap.Count;
                            continue;
                        }
                        var s = (n + Am[i] - 1) / Am[i];
                        var ab = ~Ap.BinarySearch(s, lb);
                        cnt += ab;
                    }
                    return cnt < mNum - k + 1;
                };
                WriteLine(-bSearch(0, (long)1e18 + 1, K, IsOk));
            }
        }
        static long bSearch(long ok, long ng, long k, Func<long, long, bool> isOk)
        {
            while (1 < Abs(ok - ng))
            {
                var mid = (ok + ng) / 2;
                if (isOk(mid, k))
                    ok = mid;
                else
                    ng = mid;
            }
            return ok;
        }
        public class lb<T> : IComparer<T> where T : IComparable<T>
        {
            public int Compare(T x, T y) => 0 <= x.CompareTo(y) ? 1 : -1;
        }
    }
}