import sys



input = sys.stdin.readline





def read_values():

    return list(map(int, input().split()))





def read_list():

    return list(read_values())





def func(N, mod):

    F = [1]

    for i in range(1, N + 1):

        F.append(F[-1] * i % mod)

    return F





INV = {}





def inv(a, mod):

    if a in INV:

        return INV[a]

    r = pow(a, mod - 2, mod)

    INV[a] = r

    return r





def C(F, a, b, mod):

    return F[a] * inv(F[b], mod) * inv(F[a - b], mod) % mod





def main():

    N, W = read_values()

    dp = [

        [[0 for _ in range(N * 3 + 10)] for __ in range(N + 10)]

        for ___ in range(N + 10)

    ]

    I = [tuple(read_values()) for _ in range(N)]



    w0 = I[0][0]

    if w0 > W:

        print((0))

        return



    for i, (w1, v) in enumerate(I):

        w = w1 - w0

        for k in range(N):

            for j in range(N * 3 + 5):

                dp[i + 1][k][j] = max(dp[i][k][j], dp[i + 1][k][j])

                dp[i + 1][k + 1][j + w] = max(dp[i][k][j] + v, dp[i + 1][k + 1][j + w])



    res = 0

    for k in range(N + 1):

        r = min(W - k * w0, 3 * N + 5)

        if r < 0:

            continue

        for i in range(r + 1):

            res = max(res, dp[N][k][i])

    print(res)





if __name__ == "__main__":

    main()



import sys



input = sys.stdin.readline





def read_values():

    return list(map(int, input().split()))





def read_list():

    return list(read_values())





def func(N, mod):

    F = [1]

    for i in range(1, N + 1):

        F.append(F[-1] * i % mod)

    return F





INV = {}





def inv(a, mod):

    if a in INV:

        return INV[a]

    r = pow(a, mod - 2, mod)

    INV[a] = r

    return r





def C(F, a, b, mod):

    return F[a] * inv(F[b], mod) * inv(F[a - b], mod) % mod





def main():

    import bisect



    N, W = read_values()

    I = [tuple(read_values()) for _ in range(N)]



    init_w = I[0][0]

    D = {i: [] for i in range(4)}

    S = {i: [0] for i in range(4)}

    for w, v in I:

        bisect.insort(D[w - init_w], -v)



    for i, d in list(D.items()):

        for v in d:

            S[i].append(v + S[i][-1])



    res = 0

    for t0 in range(len(D[0]) + 1):

        for t1 in range(len(D[1]) + 1):

            for t2 in range(len(D[2]) + 1):

                for t3 in range(len(D[3]) + 1):

                    if (t0 + t1 + t2 + t3) * init_w + t1 + 2 * t2 + 3 * t3 > W:

                        continue



                    res = min(res, S[0][t0] + S[1][t1] + S[2][t2] + S[3][t3])

    print((-res))





if __name__ == "__main__":

    main()



import sys

input = sys.stdin.readline


def read_values():
    return list(map(int, input().split()))


def read_list():
    return list(read_values())


def func(N, mod):
    F = [1]
    for i in range(1, N + 1):
        F.append(F[-1] * i % mod)
    return F


INV = {}


def inv(a, mod):
    if a in INV:
        return INV[a]
    r = pow(a, mod - 2, mod)
    INV[a] = r
    return r


def C(F, a, b, mod):
    return F[a] * inv(F[b], mod) * inv(F[a - b], mod) % mod


def main():
    N, W = read_values()
    dp = [
        [[0 for _ in range(N * 3 + 10)] for __ in range(N + 10)]
        for ___ in range(N + 10)
    ]
    I = [tuple(read_values()) for _ in range(N)]
    w0 = I[0][0]
    if w0 > W:
        print((0))
        return
    for i, (w1, v) in enumerate(I):
        w = w1 - w0
        for k in range(N):
            for j in range(N * 3 + 5):
                dp[i + 1][k][j] = max(dp[i][k][j], dp[i + 1][k][j])
                dp[i + 1][k + 1][j + w] = max(dp[i][k][j] + v, dp[i + 1][k + 1][j + w])
    res = 0
    for k in range(N + 1):
        r = min(W - k * w0, 3 * N + 5)
        if r < 0:
            continue
        for i in range(r + 1):
            res = max(res, dp[N][k][i])
    print(res)


if __name__ == "__main__":
    main()

import sys

input = sys.stdin.readline


def read_values():
    return list(map(int, input().split()))


def read_list():
    return list(read_values())


def func(N, mod):
    F = [1]
    for i in range(1, N + 1):
        F.append(F[-1] * i % mod)
    return F


INV = {}


def inv(a, mod):
    if a in INV:
        return INV[a]
    r = pow(a, mod - 2, mod)
    INV[a] = r
    return r


def C(F, a, b, mod):
    return F[a] * inv(F[b], mod) * inv(F[a - b], mod) % mod


def main():
    import bisect

    N, W = read_values()
    I = [tuple(read_values()) for _ in range(N)]
    init_w = I[0][0]
    D = {i: [] for i in range(4)}
    S = {i: [0] for i in range(4)}
    for w, v in I:
        bisect.insort(D[w - init_w], -v)
    for i, d in list(D.items()):
        for v in d:
            S[i].append(v + S[i][-1])
    res = 0
    for t0 in range(len(D[0]) + 1):
        for t1 in range(len(D[1]) + 1):
            for t2 in range(len(D[2]) + 1):
                for t3 in range(len(D[3]) + 1):
                    if (t0 + t1 + t2 + t3) * init_w + t1 + 2 * t2 + 3 * t3 > W:
                        continue
                    res = min(res, S[0][t0] + S[1][t1] + S[2][t2] + S[3][t3])
    print((-res))


if __name__ == "__main__":
    main()

+    import bisect + -    dp = [ -        [[0 for _ in range(N * 3 + 10)] for __ in range(N + 10)] -        for ___ in range(N + 10) -    ] -    w0 = I[0][0] -    if w0 > W: -        print((0)) -        return -    for i, (w1, v) in enumerate(I): -        w = w1 - w0 -        for k in range(N): -            for j in range(N * 3 + 5): -                dp[i + 1][k][j] = max(dp[i][k][j], dp[i + 1][k][j]) -                dp[i + 1][k + 1][j + w] = max(dp[i][k][j] + v, dp[i + 1][k + 1][j + w]) +    init_w = I[0][0] +    D = {i: [] for i in range(4)} +    S = {i: [0] for i in range(4)} +    for w, v in I: +        bisect.insort(D[w - init_w], -v) +    for i, d in list(D.items()): +        for v in d: +            S[i].append(v + S[i][-1]) -    for k in range(N + 1): -        r = min(W - k * w0, 3 * N + 5) -        if r < 0: -            continue -        for i in range(r + 1): -            res = max(res, dp[N][k][i]) -    print(res) +    for t0 in range(len(D[0]) + 1): +        for t1 in range(len(D[1]) + 1): +            for t2 in range(len(D[2]) + 1): +                for t3 in range(len(D[3]) + 1): +                    if (t0 + t1 + t2 + t3) * init_w + t1 + 2 * t2 + 3 * t3 > W: +                        continue +                    res = min(res, S[0][t0] + S[1][t1] + S[2][t2] + S[3][t3]) +    print((-res))