// Slower C++ solution:
#include <bits/stdc++.h>

using namespace std;



#define NDEBUG

#ifdef DEBUG

#include "../cout11.h"

#undef NDEBUG

#endif

#include <cassert>



typedef long long ll;

typedef long double Double;

typedef unsigned long long ull;

typedef pair<int,int> ii;

typedef pair<ll,ll> llll;

typedef pair<double,double> dd;



typedef vector<int> vi;

typedef vector<vector<int>> vvi;

typedef vector<ii> vii;

typedef vector<vector<ii>> vvii;

typedef vector<ll> vll;

typedef vector<string> vs;

typedef vector<double> vd;

typedef vector<long double> vD;



#define sz(a)  int((a).size())

#define pb  push_back

#define FOR(var,from,to) for(int var=(from);var<=(to);++var)

#define rep(var,n)  for(int var=0;var<(n);++var)

#define rep1(var,n)  for(int var=1;var<=(n);++var)

#define repC2(vari,varj,n)  for(int vari=0;vari<(n)-1;++vari)for(int varj=vari+1;varj<(n);++varj)

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

#define RALL(c)  (c).rbegin(),(c).rend()

#define tr(i,c)  for(auto i=(c).begin(); i!=(c).end(); ++i)

#define found(s,e)  ((s).find(e)!=(s).end())

#define mset(arr,val)  memset(arr,val,sizeof(arr))

#define mid(x,y) ((x)+((y)-(x))/2)

#define IN(x,a,b) ((a)<=(x)&&(x)<=(b))



ll gcd(ll a, ll b) { while(a) swap(a, b%=a); return b; }



const ll MOD=1000000007LL;



ll ADD(ll x, ll y) { return (x+y) % MOD; }

ll SUB(ll x, ll y) { return (x-y+MOD) % MOD; }

ll MUL(ll x, ll y) { return x*y % MOD; }

ll POW(ll x, ll e) { ll v=1; for(; e; x=MUL(x,x), e>>=1) if (e&1) v = MUL(v,x); return v; }

ll DIV(ll x, ll y) { /*assert(y%MOD!=0);*/ return MUL(x, POW(y, MOD-2)); }

// ll comb(ll n, ll k) { ll v=1; for(ll i=1; i<=k; i++) v = DIV(MUL(v, n-i+1),i); return v; }

//



ll solve(int N,int W,vi& w,vi& v){

    int w0 = w[0];

    vi dw(N); rep(i,N) dw[i] = w[i] - w0;



    vvi dp(101, vi(301, -1));

    // dp[個数][Σdw] = Σv

    dp[0][0] = 0;

    rep(i, N) {

        // vvi dp2(101, vi(300, 0));

        int dw_i = dw[i];

        int v_i = v[i];

        for (int k=i; k>=0; --k) {

            for (int j=0; j<=300; ++j) {

                if (dp[k][j] == -1) continue;

                if (j+dw_i <= 300) {

                    dp[k+1][j+dw_i] = max(dp[k+1][j+dw_i], dp[k][j] + v_i);

                }

            }

        }

    }



    int ans = 0;

    for (int k=0; k<=100; ++k) {

        ll base = (ll)w0 * k;

        ll room = W - base;

        if (room < 0) break;

        int rmax = min(300, (int)room);

        // dp[k][0] .. dp[k][room]

        int best = 0;

        for (int j=0; j<=rmax; ++j) {

            if (dp[k][j] == -1) continue;

            best = max(best, dp[k][j]);

        }

        // fprintf(stderr, "k=%d, best=%d\n", k,best);

        ans = max(ans, best);

    }

    return ans;

}



int main() {

    int N, W; cin >> N >> W;

    vi w(N), v(N);

    rep(i,N) cin >> w[i] >> v[i];

    cout << solve(N,W,w,v) << endl;

    return 0;

}


// Faster C++ solution for the same problem (measured speedup: 1.1362700705008186x):
#include <bits/stdc++.h>

using namespace std;



#define NDEBUG

#ifdef DEBUG

#include "../cout11.h"

#undef NDEBUG

#endif

#include <cassert>



typedef long long ll;

typedef long double Double;

typedef unsigned long long ull;

typedef pair<int,int> ii;

typedef pair<ll,ll> llll;

typedef pair<double,double> dd;



typedef vector<int> vi;

typedef vector<vector<int>> vvi;

typedef vector<ii> vii;

typedef vector<vector<ii>> vvii;

typedef vector<ll> vll;

typedef vector<string> vs;

typedef vector<double> vd;

typedef vector<long double> vD;



#define sz(a)  int((a).size())

#define pb  push_back

#define FOR(var,from,to) for(int var=(from);var<=(to);++var)

#define rep(var,n)  for(int var=0;var<(n);++var)

#define rep1(var,n)  for(int var=1;var<=(n);++var)

#define repC2(vari,varj,n)  for(int vari=0;vari<(n)-1;++vari)for(int varj=vari+1;varj<(n);++varj)

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

#define RALL(c)  (c).rbegin(),(c).rend()

#define tr(i,c)  for(auto i=(c).begin(); i!=(c).end(); ++i)

#define found(s,e)  ((s).find(e)!=(s).end())

#define mset(arr,val)  memset(arr,val,sizeof(arr))

#define mid(x,y) ((x)+((y)-(x))/2)

#define IN(x,a,b) ((a)<=(x)&&(x)<=(b))



ll gcd(ll a, ll b) { while(a) swap(a, b%=a); return b; }



const ll MOD=1000000007LL;



ll ADD(ll x, ll y) { return (x+y) % MOD; }

ll SUB(ll x, ll y) { return (x-y+MOD) % MOD; }

ll MUL(ll x, ll y) { return x*y % MOD; }

ll POW(ll x, ll e) { ll v=1; for(; e; x=MUL(x,x), e>>=1) if (e&1) v = MUL(v,x); return v; }

ll DIV(ll x, ll y) { /*assert(y%MOD!=0);*/ return MUL(x, POW(y, MOD-2)); }

// ll comb(ll n, ll k) { ll v=1; for(ll i=1; i<=k; i++) v = DIV(MUL(v, n-i+1),i); return v; }

//



ll solve(int N,int W,vi& w,vi& v){

    int w0 = w[0];

    // vi dw(N); rep(i,N) dw[i] = w[i] - w0;

    vvi dw(4, vi());

    rep(i,N){

        dw[w[i] - w0].pb(v[i]);

    }

    vi dwn(4);

    rep(i,4){

        sort(ALL(dw[i]));

        dw[i].pb(0);

        reverse(ALL(dw[i]));

        dwn[i] = dw[i].size();

        // accum

        rep(j,dwn[i]-1) {

            dw[i][j+1] += dw[i][j];

        }

#ifdef DEBUG

        cerr << i << " " << dwn[i] << " " << dw[i] << endl;

#endif

    }

    int best = 0;

    for (int a=0; a<dwn[0]; ++a)

    for (int b=0; b<dwn[1]; ++b)

    for (int c=0; c<dwn[2]; ++c)

    for (int d=0; d<dwn[3]; ++d) {

        int vsum = dw[0][a] + dw[1][b] + dw[2][c] + dw[3][d];

        ll wsum = (a*0 + b*1 + c*2 + d*3) + (ll)w0*(a+b+c+d);

        if (wsum <= W) best = max(best, vsum);

    }

    return best;

}



int main() {

    int N, W; cin >> N >> W;

    vi w(N), v(N);

    rep(i,N) cin >> w[i] >> v[i];

    cout << solve(N,W,w,v) << endl;

    return 0;

}