import std.algorithm;
import std.array;
import std.conv;
import std.math;
import std.range;
import std.stdio;
import std.string;
import std.typecons;

T read(T)() { return readln.chomp.to!T; }
T[] reads(T)() { return readln.split.to!(T[]); }
alias readint = read!int;
alias readints = reads!int;

alias Item = Tuple!(int, "weight", long[], "values");

long calc(int W, Item[] items) {

    long rec(int p, long weight, long value) {
        if (p == items.length) return value;

        long ans = rec(p + 1, weight, value); // p 番目は使わないときの解
        auto w = items[p].weight;
        auto v = items[p].values;
        for (int i = 0; i < v.length; i++) {
            long w2 = weight + w * (i + 1);
            if (w2 > W) break;

            long v2 = value + v[i];
            ans = max(ans, rec(p + 1, w2, v2));
        }
        return ans;
    }

    return rec(0, 0, 0);
}

void main() {
    auto nw = readints;
    int n = nw[0], W = nw[1];

    int[][int] d;
    for (int i = 0; i < n; i++) {
        auto wv = readints;
        int w = wv[0], v = wv[1];
        d[w] ~= v;
    }

    Item[] items;
    foreach (k, v; d) {
        long[] t = v.dup.to!(long[]);
        t.sort();
        t.reverse();
        for (int i = 1; i < t.length; i++) {
            t[i] += t[i-1];
        }
        items ~= Item(k, t);
    }

    writeln(calc(W, items));
}
