Buggy python submission (verdict: Time Limit Exceeded):
n,k=map(int,input().split())
a=list(map(int,input().split()))
from math import log2
from bisect import bisect_left,bisect_right
a.sort()
# 0未満の個数
mn=bisect_left(a,0)
# 0の個数
zn=bisect_right(a,0)-mn
# 0より大きい個数
pn=n-mn-zn
am=a[:mn]
am=[-x for x in am[::-1]]
ap=a[mn+zn:]
# 自分より小さい数字がk個未満のうち最大の値を求める
# 自分より小さい数字がk個未満ならTrue
def func(x):
    cnt=0
    if x>0:
        cnt+=mn*pn
        cnt+=(zn*(n-1+n-zn))//2
        cnt1=0
        for y in ap:
            cnt1+=bisect_left(ap,(x+y-1)//y)
            if y**2<x:cnt1-=1
        for y in am:
            cnt1+=bisect_left(am,(x+y-1)//y)
            if y**2<x:cnt1-=1
        cnt+=cnt1//2
    elif x<0:
        x=abs(x)
        for y in ap:
            cnt+=mn-bisect_right(am,x//y)
    elif x==0:
        cnt+=mn*pn
    return cnt<k

if mn*pn<k:
    l,r=0,max(a[0]*a[1],a[-1]*a[-2])+1
else:
    l,r=a[0]*a[-1]-1,0
while r-l>1:
    x=(l+r)//2
    if func(x):
        l,r=x,r
    else:
        l,r=l,x
print(l)

Fixed submission:
import numpy as np
n,k=map(int,input().split())
a=np.array(list(map(int,input().split())))
a.sort()
p=a[a>0]
z=np.count_nonzero(a==0)
m=a[a<0]
r=10**19
l=-r
while r-l>1:
    # 区間[l,r]を半分に分けて探索。最終的にrが求める値になるようにする。
    # b以下のものがk個以上あるような、最小のbを求める。bを大きくする→b以下のものも増える。b以下のものがめちゃくちゃある→bを減らす。
    b=(l+r)//2
    c=0
    if b>=0:
        c+=z*n
    # 配列aに対し、配列b//pの要素たちをそれぞれsearchsortedする。結果の配列はb//pと同じ形になる。
    c+=a.searchsorted(b//p,side='right').sum()
    # 配列aに対し、配列b//mの要素たちをそれぞれsearchsortedする。結果の配列はb//mと同じ形になる。
    c+=n*len(m)-a.searchsorted(-(-b//m),side='left').sum()
    c-=np.count_nonzero(a*a<=b)
    if c//2>=k:
        r=b
    else:
        l=b
print(r)

Buggy python submission (verdict: Time Limit Exceeded):
n,k=map(int,input().split())
a=list(map(int,input().split()))
from math import log2
from bisect import bisect_left,bisect_right
a.sort()
# 0未満の個数
mn=bisect_left(a,0)
# 0の個数
zn=bisect_right(a,0)-mn
# 0より大きい個数
pn=n-mn-zn
am=a[:mn]
am=[-x for x in am[::-1]]
ap=a[mn+zn:]
# 自分より小さい数字がk個未満のうち最大の値を求める
# 自分より小さい数字がk個未満ならTrue
def func(x):
    cnt=0
    if x>0:
        cnt+=mn*pn
        cnt+=(zn*(n-1+n-zn))//2
        cnt1=0
        for y in ap:
            cnt1+=bisect_left(ap,(x+y-1)//y)
            if y**2<x:cnt1-=1
        for y in am:
            cnt1+=bisect_left(am,(x+y-1)//y)
            if y**2<x:cnt1-=1
        cnt+=cnt1//2
    elif x<0:
        x=abs(x)
        for y in ap:
            cnt+=mn-bisect_right(am,x//y)
    elif x==0:
        cnt+=mn*pn
    return cnt<k

if mn*pn<k:
    l,r=0,max(a[0]*a[1],a[-1]*a[-2])
else:
    l,r=a[0]*a[-1],0
while r-l>1:
    x=(l+r)//2
    if func(x):
        l,r=x,r
    else:
        l,r=l,x
print(r if func(r) else l)


Fixed submission:
import numpy as np
n,k=map(int,input().split())
a=np.array(list(map(int,input().split())))
a.sort()
p=a[a>0]
z=np.count_nonzero(a==0)
m=a[a<0]
r=10**19
l=-r
while r-l>1:
    # 区間[l,r]を半分に分けて探索。最終的にrが求める値になるようにする。
    # b以下のものがk個以上あるような、最小のbを求める。bを大きくする→b以下のものも増える。b以下のものがめちゃくちゃある→bを減らす。
    b=(l+r)//2
    c=0
    if b>=0:
        c+=z*n
    # 配列aに対し、配列b//pの要素たちをそれぞれsearchsortedする。結果の配列はb//pと同じ形になる。
    c+=a.searchsorted(b//p,side='right').sum()
    # 配列aに対し、配列b//mの要素たちをそれぞれsearchsortedする。結果の配列はb//mと同じ形になる。
    c+=n*len(m)-a.searchsorted(-(-b//m),side='left').sum()
    c-=np.count_nonzero(a*a<=b)
    if c//2>=k:
        r=b
    else:
        l=b
print(r)

Buggy python submission (verdict: Time Limit Exceeded):
n,k=map(int,input().split())
a=list(map(int,input().split()))
from math import log2
from bisect import bisect_left,bisect_right
a.sort()
# 0未満の個数
mn=bisect_left(a,0)
# 0の個数
zn=bisect_right(a,0)-mn
# 0より大きい個数
pn=n-mn-zn
am=a[:mn]
am=[-x for x in am[::-1]]
ap=a[mn+zn:]
# 自分より小さい数字がk個未満のうち最大の値を求める
# 自分より小さい数字がk個未満ならTrue
def func(x):
    cnt=0
    if x>0:
        cnt+=mn*pn
        cnt+=(zn*(n-1+n-zn))//2
        cnt1=0
        for y in ap:
            cnt1+=bisect_left(ap,(x+y-1)//y)
            if y**2<x:cnt1-=1
        for y in am:
            cnt1+=bisect_left(am,(x+y-1)//y)
            if y**2<x:cnt1-=1
        cnt+=cnt1//2
    elif x<0:
        x=abs(x)
        for y in ap:
            cnt+=mn-bisect_right(am,x//y)
    elif x==0:
        cnt+=mn*pn
    return cnt<k

maxaa=max(abs(a[0]),abs(a[-1]))**2
l,r=-maxaa,maxaa
while r-l>1:
    x=(l+r)//2
    if func(x):
        l,r=x,r
    else:
        l,r=l,x
print(r if func(r) else l)


Fixed submission:
import numpy as np
n,k=map(int,input().split())
a=np.array(list(map(int,input().split())))
a.sort()
p=a[a>0]
z=np.count_nonzero(a==0)
m=a[a<0]
r=10**19
l=-r
while r-l>1:
    # 区間[l,r]を半分に分けて探索。最終的にrが求める値になるようにする。
    # b以下のものがk個以上あるような、最小のbを求める。bを大きくする→b以下のものも増える。b以下のものがめちゃくちゃある→bを減らす。
    b=(l+r)//2
    c=0
    if b>=0:
        c+=z*n
    # 配列aに対し、配列b//pの要素たちをそれぞれsearchsortedする。結果の配列はb//pと同じ形になる。
    c+=a.searchsorted(b//p,side='right').sum()
    # 配列aに対し、配列b//mの要素たちをそれぞれsearchsortedする。結果の配列はb//mと同じ形になる。
    c+=n*len(m)-a.searchsorted(-(-b//m),side='left').sum()
    c-=np.count_nonzero(a*a<=b)
    if c//2>=k:
        r=b
    else:
        l=b
print(r)