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 Scala (2.11.7) (judge verdict: Wrong Answer)

import java.io._
import java.util.StringTokenizer
import scala.util.control.Breaks.{breakable,break}
import scala.collection.mutable.{Map, Stack, Queue, PriorityQueue, Set}

object Main extends App {
  val in = new InputReader(System.in)
  val pw = new PrintWriter(System.out)

  val N = in.next().toInt
  var K = in.next().toLong
  val A = new Array[Long](N)
  var zero = 0L
  var _posi = List[Long]()
  var _nega = List[Long]()
  for (i <- 0 until N) {
    val now = in.next().toLong
    A(i) = now

    if (now == 0)
      zero += 1
    else if (now < 0)
      _nega = now :: _nega
    else
      _posi = now :: _posi
  }

  val posi = _posi.toArray.sorted
  val nega = _nega.toArray.sorted.reverse

  //
  // 条件を満たす最小の値を返す
  def binarySearch(_min: Long, _max: Long, k: Long): Long = {
    def check(i: Long): Boolean = {
      var cnt = 0

      var pos = 0
      var neg = 0
      while (neg < negaNum) {
        if (nega(neg) * posi(pos) <= i) {
          if (pos == posiNum - 1) {
            cnt += pos+1
            neg += 1
          }
          else
            pos += 1
        }
        else {
          cnt += pos
          neg += 1
        }
      }

      cnt >= k
    }

    def func(min: Long, max: Long): Long = {
      val mid: Long = (max + min) / 2
        (max - min) match{
        case 0 | 1 =>
          check(min) match{
            case true  => min
            case false => max
          }
        case _ =>
          (check(mid)) match{
            case true  => func(min, mid)
            case false => func(mid, max)
          }
      }
    }

    func(_min, _max)
  }

  // 条件を満たす最小の値を返す
  def binarySearch2(_min: Long, _max: Long, k: Long): Long = {
    def check(i: Long): Boolean = {
      var cnt = 0

      var l = 0; var r = posiNum - 1
      while (r >= 0) {
        if (posi(l) * posi(r) <= i) {
          if (l == posiNum - 1) {
            cnt += l
            r -= 1
          }
          else {
            l += 1
          }
        }
        else {
          cnt += l
          r -= 1
        }
      }

      cnt -= posi.count(n => n * n <= i)

      var res = cnt / 2
      cnt = 0

      // nega
      l = 0; r = negaNum - 1
      while (r >= 0) {
        if (nega(l) * nega(r) <= i) {
          if (l == negaNum - 1) {
            cnt += l
            r -= 1
          }
          else {
            l += 1
          }
        }
        else {
          cnt += l
          r -= 1
        }
      }

      cnt -= nega.count(n => n * n <= i)
      res += cnt / 2


      res >= k
    }

    def func(min: Long, max: Long): Long = {
      val mid: Long = (max + min) / 2
        (max - min) match{
        case 0 | 1 =>
          check(min) match{
            case true  => min
            case false => max
          }
        case _ =>
          (check(mid)) match{
            case true  => func(min, mid)
            case false => func(mid, max)
          }
      }
    }

    func(_min, _max)
  }


  val posiNum = posi.length
  val negaNum = nega.length

  var ans = 0L
  breakable {
    val minus = posiNum * negaNum
    if (K <= minus) {
      ans = binarySearch(-1e18.toLong, -1, K)
      break
    }
    K -= minus

    val hoge = zero * (posiNum + negaNum) + (zero * (zero - 1)) / 2
    if (K <= hoge) {
      ans = 0
      break
    }
    K -= hoge

    ans = binarySearch2(1, 1e18.toLong, K)
  }

  println(ans)
}

object Sub {
  def print2DimArray[A](mat: Array[Array[A]]): Unit = {
    mat.foreach(lin => println(lin.toList))
  }
}

class InputReader(stream: InputStream) {
  private[this] val reader = new BufferedReader(new InputStreamReader(stream))
  private[this] var tokenizer: StringTokenizer = new StringTokenizer(reader.readLine())
  def next(): String = {
    while (!tokenizer.hasMoreTokens()) {
      tokenizer = new StringTokenizer(reader.readLine())
    }
    tokenizer.nextToken()
  }
}