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

WV = [list(map(int,input().split())) for _ in [0]*N]



#dp[i][n:入れた数][dW:w1からの差分の合計]

dp = [[[0]*(3*N+1) for _ in [0]*(N+1)] for _ in [0]*(N+1)]

w0 = WV[0][0]

for i,wv in enumerate(WV,1):

    w,v = wv

    w -= w0

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

        for dW in range(3*N+1):

            if n*w0 + dW > W:break

            if w>dW:

                dp[i][n][dW] = dp[i-1][n][dW]

                continue

            dp[i][n][dW] = max(dp[i-1][n][dW],dp[i-1][n-1][dW-w]+v)

print((max(max(row) for row in dp[-1])))
#メモ化再帰

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

WV = [list(map(int,input().split())) for _ in [0]*N]

memo = [{} for _ in [0]*(N+1)]

def dp(i,j):

    if j<=0 or i<=0: return 0

    if j in memo[i]:return memo[i][j]

    w,v = WV[i-1]

    ret = dp(i-1,j)

    if j-w>=0: ret = max(ret,dp(i-1,j-w)+v)

    memo[i][j] = ret

    return ret

print((dp(N,W)))
N, W = list(map(int, input().split()))
WV = [list(map(int, input().split())) for _ in [0] * N]
# dp[i][n:入れた数][dW:w1からの差分の合計]
dp = [[[0] * (3 * N + 1) for _ in [0] * (N + 1)] for _ in [0] * (N + 1)]
w0 = WV[0][0]
for i, wv in enumerate(WV, 1):
    w, v = wv
    w -= w0
    for n in range(1, i + 1):
        for dW in range(3 * N + 1):
            if n * w0 + dW > W:
                break
            if w > dW:
                dp[i][n][dW] = dp[i - 1][n][dW]
                continue
            dp[i][n][dW] = max(dp[i - 1][n][dW], dp[i - 1][n - 1][dW - w] + v)
print((max(max(row) for row in dp[-1])))

# メモ化再帰
N, W = list(map(int, input().split()))
WV = [list(map(int, input().split())) for _ in [0] * N]
memo = [{} for _ in [0] * (N + 1)]


def dp(i, j):
    if j <= 0 or i <= 0:
        return 0
    if j in memo[i]:
        return memo[i][j]
    w, v = WV[i - 1]
    ret = dp(i - 1, j)
    if j - w >= 0:
        ret = max(ret, dp(i - 1, j - w) + v)
    memo[i][j] = ret
    return ret


print((dp(N, W)))

+# メモ化再帰 -# dp[i][n:入れた数][dW:w1からの差分の合計] -dp = [[[0] * (3 * N + 1) for _ in [0] * (N + 1)] for _ in [0] * (N + 1)] -w0 = WV[0][0] -for i, wv in enumerate(WV, 1): -    w, v = wv -    w -= w0 -    for n in range(1, i + 1): -        for dW in range(3 * N + 1): -            if n * w0 + dW > W: -                break -            if w > dW: -                dp[i][n][dW] = dp[i - 1][n][dW] -                continue -            dp[i][n][dW] = max(dp[i - 1][n][dW], dp[i - 1][n - 1][dW - w] + v) -print((max(max(row) for row in dp[-1]))) +memo = [{} for _ in [0] * (N + 1)] + + +def dp(i, j): +    if j <= 0 or i <= 0: +        return 0 +    if j in memo[i]: +        return memo[i][j] +    w, v = WV[i - 1] +    ret = dp(i - 1, j) +    if j - w >= 0: +        ret = max(ret, dp(i - 1, j - w) + v) +    memo[i][j] = ret +    return ret + + +print((dp(N, W)))