import sys
# from collections import defaultdict, deque
# import math
# import copy
from bisect import bisect_left, bisect_right
# import heapq

# sys.setrecursionlimit(1000000)

# input aliases
input = sys.stdin.readline

getS = lambda: input().strip()
getN = lambda: int(input())
getList = lambda: list(map(int, input().split()))
getZList = lambda: [int(x) - 1 for x in input().split()]

INF = 10 ** 20
MOD = 1000000007

def solve():
    N, W = getList()
    MI = 100
    MJ = 300
    sina = []
    w, v = getList()
    w1 = w
    v1 = v
    # sina.append((w ,v))
    for i in range(N-1):
        w, v = getList()
        sina.append((w - w1, v))

    dp = [-1 for i in range(MI*MJ+2)]
    dp[0] = 0
    dp[MJ] = v1
    for w, v in sina:
        # print(w,v)
        nxt = [-1 for i in range(MI*MJ+2)]
        for i in range(MI):
            for j in range(MJ):
                cur = dp[i*MJ + j]
                if cur != -1:
                    if nxt[i * MJ + j] < cur:
                        nxt[i * MJ + j] = cur
                    # print(cur)
                    # print(nxt[(i+1) * MJ + j + w])
                    if nxt[(i+1) * MJ + j + w] < cur + v:
                        nxt[(i + 1) * MJ + j + w] = cur + v
                        # print("update")

        dp = nxt
        # for i in range(MI):
        #     print(dp[i * MJ:i * MJ + MJ - 1])

    ans = 0
    for i in range(MI):
        for j in range(MJ):
            # print(i, j, dp[i * MJ + j])
            if w1 * i + j <= W:

                if dp[i*MJ + j] > ans:
                    # print(dp[i+MJ + j])
                    ans = dp[i * MJ + j]

    print(ans)






def main():
    n = getN()
    for _ in range(n):
        solve()
if __name__ == "__main__":
    # main()
    solve()


### FIXED CODE ###

import sys
# from collections import defaultdict, deque
# import math
# import copy
from bisect import bisect_left, bisect_right
# import heapq

# sys.setrecursionlimit(1000000)

# input aliases
input = sys.stdin.readline

getS = lambda: input().strip()
getN = lambda: int(input())
getList = lambda: list(map(int, input().split()))
getZList = lambda: [int(x) - 1 for x in input().split()]

INF = 10 ** 20
MOD = 1000000007

def solve():
    N, W = getList()
    MI = 100
    MJ = 300
    sina = []
    w, v = getList()
    w1 = w
    v1 = v
    # sina.append((w ,v))
    for i in range(N-1):
        w, v = getList()
        sina.append((w - w1, v))

    dp = [-1 for i in range(MI*MJ+MI+MJ)]
    dp[0] = 0
    dp[MJ] = v1
    for w, v in sina:
        # print(w,v)
        nxt = [-1 for i in range(MI*MJ+MI+MJ)]
        for i in range(MI):
            for j in range(MJ):
                cur = dp[i*MJ + j]
                if cur != -1:
                    if nxt[i * MJ + j] < cur:
                        nxt[i * MJ + j] = cur
                    # print(cur)
                    # print(nxt[(i+1) * MJ + j + w])
                    if nxt[(i+1) * MJ + j + w] < cur + v:
                        nxt[(i + 1) * MJ + j + w] = cur + v
                        # print("update")

        dp = nxt
        # for i in range(MI):
        #     print(dp[i * MJ:i * MJ + MJ - 1])

    ans = 0
    for i in range(MI):
        for j in range(MJ):
            # print(i, j, dp[i * MJ + j])
            if w1 * i + j <= W:

                if dp[i*MJ + j] > ans:
                    # print(dp[i+MJ + j])
                    ans = dp[i * MJ + j]

    print(ans)






def main():
    n = getN()
    for _ in range(n):
        solve()
if __name__ == "__main__":
    # main()
    solve()