// Original C++ solution (slower):
#include <algorithm>

#include <iostream>

#include <vector>

#define REP(i, n) for (int i = 0; i < (int)(n); ++i)

using namespace std;

typedef long long ll;



void iostream_init() {

    ios::sync_with_stdio(false);

    cin.tie(0);

    cout.setf(ios::fixed);

    cout.precision(12);

}



class Knapsack {

    struct item {

        ll v, w;

    };



    vector<item> items;

    ll W, lv;



    ll solve_rec(size_t k, ll v, ll w) {

        if (w + items[k].w > W)

            return solve_rec(k + 1, v, w);

        ll cv = v, cw = w;

        for (size_t i = k; i < items.size(); ++i) {

            if (cw + items[i].w <= W) {

                cw += items[i].w;

                cv += items[i].v;

            }

        }

        if (lv < cv)

            lv = cv;

        double fv = v, fw = w;

        for (size_t i = k; i < items.size(); ++i) {

            if (fw + items[i].w <= W) {

                fw += items[i].w;

                fv += items[i].v;

            } else {

                fv += items[i].v * (W - fw) / items[i].w;

                break;

            }

        }

        if (fv - lv < 1 || fv < lv)

            return lv;

        solve_rec(k + 1, v + items[k].v, w + items[k].w);

        return solve_rec(k + 1, v, w);

    }



  public:

    // 価値v, 重みwのアイテムを追加

    void add_item(ll v, ll w) { items.push_back({v, w}); }



    // 重みの合計がW以下になるようにアイテムを選んだときの価値の和の最大値を返す．

    ll solve(ll W_) {

        if (items.empty())

            return 0;

        W = W_;

        sort(items.begin(), items.end(), [](const item &a, const item &b) {

            return a.v * b.w > a.w * b.v;

        });

        lv = 0;

        return solve_rec(0, 0, 0);

    };

};



int main() {

    iostream_init();

    int N, W;

    cin >> N >> W;

    Knapsack dp;

    for (int i = 0; i < N; i++) {

        int w, v;

        cin >> w >> v;

        dp.add_item(v, w);

    }



    cout << dp.solve(W) << endl;

    return 0;

}

// Optimized solution to the same problem (faster):
#include <algorithm>

#include <cstdio>

#include <vector>



typedef long long int ll;



struct state {

    ll aw;

    ll av;

    state(ll aw = 0, ll av = 0) : aw(aw), av(av) {}

};



struct item {

    int w;

    int v;

    double d;

    item(int w, int v) : w(w), v(v), d((double)v / w) {}

};



int n, w;



ll lower;



std::vector<item> is;

std::vector<state> dp[2];



void add(const std::vector<state> &s, const item &k, std::vector<state> &u,

         ll uw) {

    auto i = s.cbegin();

    auto j = s.cbegin();

    while (i != s.cend() && j != s.cend()) {

        if (i->aw > uw) {

            i = s.cend();

            break;

        }

        ll jav = j->av + k.v;

        ll jaw = j->aw + k.w;

        if (jaw > uw) {

            j = s.cend();

            break;

        }

        if (i->aw <= jaw && i->av >= jav) {

            ++j;

        } else if (i->aw >= jaw && i->av <= jav) {

            ++i;

        } else if (i->aw < jaw) {

            u.push_back(*i++);

        } else {

            u.emplace_back(state(jaw, jav));

            ++j;

        }

    }

    while (i != s.cend()) {

        if (i->aw > uw)

            return;

        u.push_back(*i++);

    }

    while (j != s.cend()) {

        ll jav = j->av + k.v;

        ll jaw = j->aw + k.w;

        if (jaw > uw)

            return;

        u.emplace_back(state(jaw, jav));

        ++j;

    }

}



void remove(const std::vector<state> &s, const item &k, std::vector<state> &u,

            ll uw) {

    auto i = s.cbegin();

    auto j = s.cbegin();

    while (i != s.cend() && j != s.cend()) {

        if (i->aw > uw) {

            i = s.cend();

            break;

        }

        ll jav = j->av - k.v;

        ll jaw = j->aw - k.w;

        if (jaw > uw) {

            j = s.cend();

            break;

        }

        if (i->aw <= jaw && i->av >= jav) {

            ++j;

        } else if (i->aw >= jaw && i->av <= jav) {

            ++i;

        } else if (i->aw < jaw) {

            u.push_back(*i++);

        } else {

            u.emplace_back(state(jaw, jav));

            ++j;

        }

    }

    while (i != s.cend()) {

        if (i->aw > uw)

            return;

        u.push_back(*i++);

    }

    while (j != s.cend()) {

        ll jav = j->av - k.v;

        ll jaw = j->aw - k.w;

        if (jaw > uw)

            return;

        u.emplace_back(state(jaw, jav));

        ++j;

    }

}



ll upper;



inline void shrink(const std::vector<state> &s, double d0, double d1,

                   std::vector<state> &u) {

    for (auto x : s) {

        ll t = (x.aw > w) ? x.av - (x.aw - w) * d0 : x.av + (w - x.aw) * d1;

        if (t >= lower)

            u.push_back(x);

        if (t > upper)

            upper = t;

    }

}



int main() {

    scanf("%d%d", &n, &w);

    is.reserve(200);

    dp[0].reserve(300);

    dp[1].reserve(300);



    is.emplace_back(item(1, 0));



    for (int i = 0; i < n; i++) {

        int ww, vv;

        scanf("%d%d", &ww, &vv);

        if (ww <= w)

            is.emplace_back(item(ww, vv));

    }

    n = is.size() - 1;



    std::sort(is.begin() + 1, is.end(),

              [](const item &x, const item &y) { return x.d > y.d; });

    is.emplace_back(item(1, 0));



    ll aw = 0;

    ll av = 0;

    int ii;

    for (ii = 1; ii <= n; ii++) {

        const item &x = is[ii];

        if (aw + x.w > w)

            break;

        aw += x.w;

        av += x.v;

    }



    dp[0].emplace_back(state(aw, av));



    lower = av;

    ll sumw = w + aw;



    for (int i = ii - 1, j = ii; i > 0 || j <= n;) {

        if (i > 0) {

            sumw -= is[i].w;

            remove(dp[0], is[i], dp[1], sumw);

            dp[0].resize(0);

            lower = (std::upper_bound(

                         dp[1].cbegin(), dp[1].cend(), w,

                         [](int w, const state &x) { return x.aw > w; }) -

                     1)

                        ->av;

            shrink(dp[1], is[i - 1].d, is[j].d, dp[0]);

            dp[1].resize(0);

            --i;

        }



        if (j <= n) {

            add(dp[0], is[j], dp[1], sumw);

            dp[0].resize(0);

            lower = (std::upper_bound(

                         dp[1].cbegin(), dp[1].cend(), w,

                         [](int w, const state &x) { return x.aw > w; }) -

                     1)

                        ->av;

            shrink(dp[1], is[i].d, is[j + 1].d, dp[0]);

            dp[1].resize(0);

            ++j;

        }

        if (lower == upper)

            break;

    }



    lower = (std::upper_bound(dp[0].cbegin(), dp[0].cend(), w,

                              [](int w, const state &x) { return x.aw > w; }) -

             1)

                ->av;

    printf("%lld\n", lower);



    return 0;

}

// Fastest known solution for this problem: