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

#include <iostream>

#include <vector>

using namespace std;



typedef long long ll;

typedef pair<int, int> PII;

typedef pair<ll, ll> PLL;

#define INF (1e9)

#define MOD (1e9 + 7)

#define LINF (1e18)

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

#define ALL(obj) (obj).begin(), (obj).end()

#define ALLR(obj) (obj).rbegin(), (obj).rend()



int main() {

    cin.tie(0);

    ios::sync_with_stdio(false);



    int n, max_w;

    cin >> n >> max_w;



    ll w[n], v[n];

    REP(i, n) cin >> w[i] >> v[i];



    ll max_v = 100000;

    // dp[i] : 価値iを作れるときの重さの最小値

    vector<ll> dp(max_v + 1, LINF);



    dp[0] = 0;

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

        for (int j = max_v; j >= 0; j--) {

            if (j - v[i - 1] >= 0)

                dp[j] = min(dp[j], dp[j - v[i - 1]] + w[i - 1]);

        }

    }



    ll ans = 0;

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

        if (dp[i] <= max_w)

            ans = max(ans, (ll)i);

    }



    cout << ans << endl;

}

// 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: