Buggy python submission (verdict: Time Limit Exceeded):
from bisect import bisect_left, bisect_right

N, K = map(int, input().split())
*A, = map(int, input().split())
A = sorted(A)

neg_end = bisect_left(A, 0)
pos_start = bisect_right(A, 0)
n_pos = N - pos_start
n_neg = neg_end
n_zero = N - (n_pos + n_neg)

n_prod_neg = n_pos * n_neg
n_prod_zero = n_zero * (n_pos + n_neg) + (n_zero * (n_zero - 1) // 2)

if K <= n_prod_neg: # answer is negative
    # binary search
    def cond(x):
        # two pointers technique
        counter = 0; r = pos_start
        for l in range(neg_end): # (A[l] * A[r] > x) -> (A[l+1] * A[r] > x)
            while r < N and A[l] * A[r] > x: r += 1
            counter += n_pos - (r - pos_start) # (A[l] * A[r] <= x) -> (A[l] * A[r+1] <= x)
        return counter >= K
    MAX = 0
    MIN = -10**18
    left, right = MIN, MAX # search range
    while right - left > 1:
        mid = (left + right) // 2
        if cond(mid): right = mid
        else: left = mid
    print(right)
elif K <= n_prod_neg + n_prod_zero: # answer is zero
    print(0)
else: # answer is positive
    K -= n_prod_neg + n_prod_zero
    # binary search
    def cond(x):
        # two pointers technique
        counter = 0
        r = N - 1
        for l in range(pos_start, N): # (A[l] * A[r] > x) -> (A[l+1] * A[r] > x)  (l < r)
            while l < r and A[l] * A[r] > x: r -= 1
            counter += max(0, r - l) # (A[l] * A[r] <= x) -> (A[l] * A[r-1] <= x)  (l + 1 < r)
            if l >= r: break
        l = 0
        for r in range(neg_end - 1, -1, -1): # (A[l] * A[r] > x) -> (A[l] * A[r-1] > x)  (l < r)
            while l < r and A[l] * A[r] > x: l += 1
            counter += max(0, r - l) # (A[l] * A[r] <= x) -> (A[l+1] * A[r] <= x)  (l < r - 1)
            if l >= r: break
        return counter >= K
    MAX = 10**18
    MIN = 0
    left, right = MIN, MAX # search range
    while right - left > 1:
        mid = (left + right) // 2
        if cond(mid): right = mid
        else: left = mid
    print(right)

Fixed submission:
from bisect import bisect_left, bisect_right

N, K = map(int, input().split())
*A, = map(int, input().split())
A = sorted(A)

neg_end = bisect_left(A, 0)
pos_start = bisect_right(A, 0)
n_pos = N - pos_start
n_neg = neg_end
n_zero = N - (n_pos + n_neg)

n_prod_neg = n_pos * n_neg
n_prod_zero = n_zero * (n_pos + n_neg) + (n_zero * (n_zero - 1) // 2)

if K <= n_prod_neg: # answer is negative
    # binary search
    def cond(x):
        # two pointers technique
        counter = 0; r = pos_start
        for l in range(neg_end): # (A[l] * A[r] > x) -> (A[l+1] * A[r] > x)
            while r < N and A[l] * A[r] > x: r += 1
            counter += n_pos - (r - pos_start) # (A[l] * A[r] <= x) -> (A[l] * A[r+1] <= x)
        return counter >= K
    MAX = 0
    MIN = -10**18
    left, right = MIN, MAX # search range
    while right - left > 1:
        mid = (left + right) // 2
        if cond(mid): right = mid
        else: left = mid
    print(right)
elif K <= n_prod_neg + n_prod_zero: # answer is zero
    print(0)
else: # answer is positive
    K -= n_prod_neg + n_prod_zero
    # binary search
    def cond(x):
        # two pointers technique
        counter = 0
        r = N - 1
        for l in range(pos_start, N): # (A[l] * A[r] > x) -> (A[l+1] * A[r] > x)  (l < r)
            while l < r and A[l] * A[r] > x: r -= 1
            counter += max(0, r - l) # (A[l] * A[r] <= x) -> (A[l] * A[r-1] <= x)  (l + 1 < r)
            if l >= r: break
        l = 0
        for r in range(neg_end - 1, -1, -1): # (A[l] * A[r] > x) -> (A[l] * A[r-1] > x)  (l < r)
            while l < r and A[l] * A[r] > x: l += 1
            counter += max(0, r - l) # (A[l] * A[r] <= x) -> (A[l+1] * A[r] <= x)  (l < r - 1)
            if l >= r: break
        return counter >= K
    MAX = 10**18
    MIN = 0
    left, right = MIN, MAX # search range
    while right - left > 1:
        mid = (left + right) // 2
        if cond(mid): right = mid
        else: left = mid
    print(right)