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()))

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

for i in range(N):

    wi, vi = list(map(int, input().split()))

    if i == 0:

        Item[0].append(vi)

        w_base = wi

    else:

        Item[wi - w_base].append(vi)



w0, w1, w2, w3 = Item

w0 = [0] + list(accumulate(sorted(w0, reverse=True)))

w1 = [0] + list(accumulate(sorted(w1, reverse=True)))

w2 = [0] + list(accumulate(sorted(w2, reverse=True)))

w3 = [0] + list(accumulate(sorted(w3, reverse=True)))



ans = 0

for i in range(len(w0)):

    for j in range(len(w1)):

        for k in range(len(w2)):

            tmp_weight = w_base * i + (w_base + 1) * j + (w_base + 2) * k

            if tmp_weight > W:

                continue

            tmp_ans = w0[i] + w1[j] + w2[k] + w3[min((W - tmp_weight) // (w_base + 3), len(w3) - 1)]

            ans = max(ans, tmp_ans)



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()))
Item = [[] for i in range(4)]
for i in range(N):
    wi, vi = list(map(int, input().split()))
    if i == 0:
        Item[0].append(vi)
        w_base = wi
    else:
        Item[wi - w_base].append(vi)
w0, w1, w2, w3 = Item
w0 = [0] + list(accumulate(sorted(w0, reverse=True)))
w1 = [0] + list(accumulate(sorted(w1, reverse=True)))
w2 = [0] + list(accumulate(sorted(w2, reverse=True)))
w3 = [0] + list(accumulate(sorted(w3, reverse=True)))
ans = 0
for i in range(len(w0)):
    for j in range(len(w1)):
        for k in range(len(w2)):
            tmp_weight = w_base * i + (w_base + 1) * j + (w_base + 2) * k
            if tmp_weight > W:
                continue
            tmp_ans = (
                w0[i]
                + w1[j]
                + w2[k]
                + w3[min((W - tmp_weight) // (w_base + 3), len(w3) - 1)]
            )
            ans = max(ans, tmp_ans)
print(ans)

-N, W_limit = list(map(int, input().split())) -W, V = [], [] +N, W = list(map(int, input().split())) +Item = [[] for i in range(4)] -    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] -# それぞれの重さから何個選ぶかで全探索 +    wi, vi = list(map(int, input().split())) +    if i == 0: +        Item[0].append(vi) +        w_base = wi +    else: +        Item[wi - w_base].append(vi) +w0, w1, w2, w3 = Item +w0 = [0] + list(accumulate(sorted(w0, reverse=True))) +w1 = [0] + list(accumulate(sorted(w1, reverse=True))) +w2 = [0] + list(accumulate(sorted(w2, reverse=True))) +w3 = [0] + list(accumulate(sorted(w3, reverse=True))) -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) +for i in range(len(w0)): +    for j in range(len(w1)): +        for k in range(len(w2)): +            tmp_weight = w_base * i + (w_base + 1) * j + (w_base + 2) * k +            if tmp_weight > W: +                continue +            tmp_ans = ( +                w0[i] +                + w1[j] +                + w2[k] +                + w3[min((W - tmp_weight) // (w_base + 3), len(w3) - 1)] +            ) +            ans = max(ans, tmp_ans)