from itertools import accumulate

N, W = list(map(int, input().split()))

w0, w1, w2, w3 = [], [], [], []

base_w = -1

for i in range(N):

    w, v = list(map(int, input().split()))

    if base_w < 0:

        base_w = w



    # 重みごとの箱にいれる

    w -= base_w

    if w == 0:

        w0.append(v)

    elif w == 1:

        w1.append(v)

    elif w == 2:

        w2.append(v)

    else:

        w3.append(v)



# 降順ソート

w0.sort(reverse=True)

w1.sort(reverse=True)

w2.sort(reverse=True)

w3.sort(reverse=True)



# 累積和

w0 = [0] + list(accumulate(w0))

w1 = [0] + list(accumulate(w1))

w2 = [0] + list(accumulate(w2))

w3 = [0] + list(accumulate(w3))



ans = 0

for i0 in range(len(w0)):

    for i1 in range(len(w1)):

        for i2 in range(len(w2)):

            for i3 in range(len(w3)):

                if base_w * i0 + (base_w + 1) * i1 + (base_w + 2) * i2 + (base_w + 3) * i3 > W:

                    continue

                ans = max(ans, w0[i0] + w1[i1] + w2[i2] + w3[i3])



print(ans)

from itertools import accumulate

N, W_limit = list(map(int, input().split()))

W, V = [], []

for i in range(N):

    w, v = list(map(int, input().split()))

    W.append(w)

    V.append(v)



# 基準となるW

base_W = W[0]

# 0 ~ 3の範囲に調節

W = [w - base_W for w in W]



# 重みごとに商品を分ける

Items = [[] for i in range(4)]

for w, v in zip(W, V):

    Items[w].append(v)



# 降順ソートして累積和を取っておく

Items = [[0] + sorted(x, reverse=True) for x in Items]

Items = [list(accumulate(x)) for x in Items]



# それぞれの重さから何個選ぶかで全探索

ans = 0

for w0 in range(len(Items[0])):

    for w1 in range(len(Items[1])):

        for w2 in range(len(Items[2])):

            for w3 in range(len(Items[3])):

                tmp_W = (w0 * base_W) + (w1 * (base_W + 1)) + (w2 * (base_W + 2)) + (w3 * (base_W + 3))

                if tmp_W > W_limit:

                    continue

                tmp_V = Items[0][w0] + Items[1][w1] + Items[2][w2] + Items[3][w3]

                ans = max(ans, tmp_V)



print(ans)

from itertools import accumulate

N, W = list(map(int, input().split()))
w0, w1, w2, w3 = [], [], [], []
base_w = -1
for i in range(N):
    w, v = list(map(int, input().split()))
    if base_w < 0:
        base_w = w
    # 重みごとの箱にいれる
    w -= base_w
    if w == 0:
        w0.append(v)
    elif w == 1:
        w1.append(v)
    elif w == 2:
        w2.append(v)
    else:
        w3.append(v)
# 降順ソート
w0.sort(reverse=True)
w1.sort(reverse=True)
w2.sort(reverse=True)
w3.sort(reverse=True)
# 累積和
w0 = [0] + list(accumulate(w0))
w1 = [0] + list(accumulate(w1))
w2 = [0] + list(accumulate(w2))
w3 = [0] + list(accumulate(w3))
ans = 0
for i0 in range(len(w0)):
    for i1 in range(len(w1)):
        for i2 in range(len(w2)):
            for i3 in range(len(w3)):
                if (
                    base_w * i0
                    + (base_w + 1) * i1
                    + (base_w + 2) * i2
                    + (base_w + 3) * i3
                    > W
                ):
                    continue
                ans = max(ans, w0[i0] + w1[i1] + w2[i2] + w3[i3])
print(ans)

from itertools import accumulate

N, W_limit = list(map(int, input().split()))
W, V = [], []
for i in range(N):
    w, v = list(map(int, input().split()))
    W.append(w)
    V.append(v)
# 基準となるW
base_W = W[0]
# 0 ~ 3の範囲に調節
W = [w - base_W for w in W]
# 重みごとに商品を分ける
Items = [[] for i in range(4)]
for w, v in zip(W, V):
    Items[w].append(v)
# 降順ソートして累積和を取っておく
Items = [[0] + sorted(x, reverse=True) for x in Items]
Items = [list(accumulate(x)) for x in Items]
# それぞれの重さから何個選ぶかで全探索
ans = 0
for w0 in range(len(Items[0])):
    for w1 in range(len(Items[1])):
        for w2 in range(len(Items[2])):
            for w3 in range(len(Items[3])):
                tmp_W = (
                    (w0 * base_W)
                    + (w1 * (base_W + 1))
                    + (w2 * (base_W + 2))
                    + (w3 * (base_W + 3))
                )
                if tmp_W > W_limit:
                    continue
                tmp_V = Items[0][w0] + Items[1][w1] + Items[2][w2] + Items[3][w3]
                ans = max(ans, tmp_V)
print(ans)

-N, W = list(map(int, input().split())) -w0, w1, w2, w3 = [], [], [], [] -base_w = -1 +N, W_limit = list(map(int, input().split())) +W, V = [], [] -    if base_w < 0: -        base_w = w -    # 重みごとの箱にいれる -    w -= base_w -    if w == 0: -        w0.append(v) -    elif w == 1: -        w1.append(v) -    elif w == 2: -        w2.append(v) -    else: -        w3.append(v) -# 降順ソート -w0.sort(reverse=True) -w1.sort(reverse=True) -w2.sort(reverse=True) -w3.sort(reverse=True) -# 累積和 -w0 = [0] + list(accumulate(w0)) -w1 = [0] + list(accumulate(w1)) -w2 = [0] + list(accumulate(w2)) -w3 = [0] + list(accumulate(w3)) +    W.append(w) +    V.append(v) +# 基準となるW +base_W = W[0] +# 0 ~ 3の範囲に調節 +W = [w - base_W for w in W] +# 重みごとに商品を分ける +Items = [[] for i in range(4)] +for w, v in zip(W, V): +    Items[w].append(v) +# 降順ソートして累積和を取っておく +Items = [[0] + sorted(x, reverse=True) for x in Items] +Items = [list(accumulate(x)) for x in Items] +# それぞれの重さから何個選ぶかで全探索 -for i0 in range(len(w0)): -    for i1 in range(len(w1)): -        for i2 in range(len(w2)): -            for i3 in range(len(w3)): -                if ( -                    base_w * i0 -                    + (base_w + 1) * i1 -                    + (base_w + 2) * i2 -                    + (base_w + 3) * i3 -                    > W -                ): +for w0 in range(len(Items[0])): +    for w1 in range(len(Items[1])): +        for w2 in range(len(Items[2])): +            for w3 in range(len(Items[3])): +                tmp_W = ( +                    (w0 * base_W) +                    + (w1 * (base_W + 1)) +                    + (w2 * (base_W + 2)) +                    + (w3 * (base_W + 3)) +                ) +                if tmp_W > W_limit: -                ans = max(ans, w0[i0] + w1[i1] + w2[i2] + w3[i3]) +                tmp_V = Items[0][w0] + Items[1][w1] + Items[2][w2] + Items[3][w3] +                ans = max(ans, tmp_V)