#pragma GCC optimize("O3")
#pragma comment(linker, "/stack:200000000")
#pragma GCC optimize("unroll-loops")
#include<bits/stdc++.h>
using namespace std;
// #include <ext/pb_ds/assoc_container.hpp>
// #include <ext/pb_ds/tree_policy.hpp>
// using namespace __gnu_pbds;
#define fast ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);

#define mod 1000000007
#define umod 998244353 
#define euler 2.7182818284
#define inf 1e9  
#define precision(x) cout << fixed << setprecision(x);
    
#define ll long long int
#define ld long double
#define ull unsigned long long

#define vi vector<int> // vi arr(n,0) to initialize n size vector with 0 or any
#define vll vector<ll> 
#define vpi vector<pair<int,int>>
#define vpll vector<pair<ll,ll>>
#define vvi vector<vector<int,int>>
#define vvll vector<vector<ll,ll>>
#define pi pair<int,int>
#define pll pair<ll,ll>
#define pb push_back
#define mp make_pair
#define ins insert
#define er erase
#define lb lower_bound
#define ub upper_bound
#define all(v) v.begin(), v.end()
#define srt(v) sort(all(v))
#define rsrt(v) sort(v.rbegin(),v.rend())
#define maxe max_element
#define mine min_element
#define fi first
#define se second
#define itr iterator
#define viit vector<int>::iterator // vitr ptr = v.begin()
#define vllit vector<ll>::iterator
#define mapi map<int,int>
#define mapll map<ll,ll>
#define umapi unordered_map<int,int>
#define umapll unordered_map<ll,ll>
// typedef tree<int,null_type,less<int>,rb_tree_tag, tree_order_statistics_node_update> indexed_set;
#define ook order_of_key
#define fbo find_by_order

#define read(v,n) for(int i=0;i<n;i++) {cin>>v[i];}                
                  
#define show(v)                            \
    for (auto x : v)                       \
        cout << x <<nl;                    \
    cout << nl;

#define showm(m)                           \
    for (auto x : m)                       \
        cout << x.fi <<" "<< x.se <<nl;    \
    cout << nl;

#define mem(v,i) memset(v,i,sizeof(v)) //To set all elements to 0,-1, Use mem(v,60) to initialize with inf
#define uni(v) v.erase(unique(all(v)), v.end())
#define gcd(a,b) __gcd((a),(b)) //Return 0, if both are 0
#define lcm(a, b) ((a)*(b))/gcd(a, b)

#define bpc(a) __builtin_popcount(a) // count number of 1 in binary representation 
#define bclz(x)  __builtin_clz(x) // count number of leading zero in unsigned integer

#define loop(i,a,b) for(int i=(a);i<(b);i++)
#define rloop(i,a,b) for(int i=(a);i>=(b);i--) 

#define nl "\n"
#define spc " "
#define calculate_time cerr<<((double)clock()/(double)CLOCKS_PER_SEC)<<endl;
using namespace std;
inline ll addmod(ll a,ll b) { return (a%mod + b%mod)%mod; }
inline ll submod(ll a,ll b) { return (a%mod - b%mod)%mod; }
inline ll mulmod(ll a,ll b) { return ((a%mod)*(b%mod))%mod; }
bool isPrime(int n)
{
    if(n==1) return false;
    for(int i=2;i*i<=n;i++)
    {
        if(n%i==0) return false;
    }
    return true;
}

//----####Find prime by sieve###-------
// bool ar[1000001]; // In global bool array is initialized by false
// vi Pri;
// void sieve()
// {   // false-prime true-composite
//     int maxN = 1000000; ar[0] = true; ar[1] = true;
//     for(int i=2;i*i<=maxN;i++)
//     {
//         if(ar[i]==false)
//         {
//             for(int j=i*i;j<=maxN;j+=i) { ar[j] = true };
//         }
//     }
//     for(int i=1;i<1000001;i++){
//         if(ar[i]==false) Pri.pb(i);
//     }
// }

//---####Factorization####----
// int ar[1000001];
// void sieve()
// {   //Prime Factorization using sieve
//     int maxN = 1000001;
//     mem(ar,-1);
//     for(int i=2;i<=maxN;i++)
//     {
//         if(ar[i]== -1)
//         {
//             for(int j=i;j<=maxN;j++) 
//             {
//                 if(ar[j] == -1)
//                 { ar[j] = i; }
//             }
//         }
//     }
// }

//---####DSU####----
// int parent[100001];
// int R[100001]; // Initalize prarent by -1 and Rank(size) by 1 in main()
// int Find(int a)
// {   // return parent of set // Path Compression  
//     if(parent[a]<0) return a;

//     return parent[a] = Find(parent[a]);
// }

// void Union(int a,int b)
// {   //Union by rank
//     a = Find(a); b = Find(b);
//     if(a==b) return;
//     if(R[a]>R[b])
//     {
//         parent[b] = a; R[a]+=R[b];
//     }
//     else
//     {
//         parent[a] = b; R[b]+=R[a];
//     }
// }

// for(int i=1;i<=n;i++)
// {
//     cin>>a>>b; a = Find(a); b = Find(b);
//     if(a!=b) { Union(a,b); }
// }

//-----#####LCA####--------
// const int NN = 10000;
// const int maxN = log2(NN); //N is no of nodes
// int level[NN+1];
// int DP[NN+1][maxN];
// void dfss(int node,int lvl,int par)
// {
//     DP[node][0] = par; level[node] = lvl;
//     for(auto child : adj[node]){
//         if(child!=par) dfss(child,lvl+1,node);
//     }
// }
// void prelca()
// {
//     dfss(1,0,-1);
//     for(int j=1;j<=maxN;j++){
//         for(int i=1;i<=NN;i++){
//             if(DP[i][j-1]!=-1){
//                 DP[i][j] = DP[ DP[i][j-1] ][j-1];
//             }
//         }
//     }
// }
// int lca(int a,int b)
// {
//     if(level[a]>level[b]) swap(a,b);
//     int d = level[b] - level[a];
//     while(d>0){
//         int i = log2(d);
//         b = DP[b][i];
//         d-=(1<<i);
//     }
//     if(a==b) return a;
//     for(int i=maxN;i>=0;i--){
//         if(DP[a][i]!=-1 && (DP[a][i]!=DP[b][i])){
//             a = DP[a][i]; b = DP[b][i];
//         }
//     }
//     return DP[a][0];
// }

//----####Factors####------
vi factors(int n)
{   //Finding factors of n
    vi fact;
    for(int i=1;i*i<=n;i++)
    {
        if(n%i==0)
        {
            fact.pb(i);
            if(i*i!=n) { fact.pb(n/i); }
        }
    }
    return fact;
}

//---####power a^b under modulo####---
ll pw(ll a,ll b)
{
    ll res = 1;
    while (b > 0)  
    {  
       if (b & 1){  
            res = (res*a);
        }    
        b = b>>1;  
        a = (a*a);  
    }  
    return res;
}

ll pwmod(ll a,ll b)  // a^b with mod
{  
    ll res = 1; a = a%mod;  
    while (b > 0)  
    {  
       if (b & 1){  
            res = (res*a) % mod;
        }    
        b = b>>1;  
        a = (a*a) % mod;  
    }  
    return res;  
}

ll modinv(ll a)
{
    return pwmod(a,mod-2); //GCD(a,mod)=1
}

ll dp[101][100001];
ll kp(ll wt[],ll val[],ll n,ll w)
{
    if(n==0||w==0)
        return 0;
    if(dp[n][w]!=-1)
        return dp[n][w];
    if(wt[n-1]<=w)
    {
        return dp[n][w] = max( val[n-1] + kp(wt,val,n-1,w-wt[n-1]) , kp(wt,val,n-1,w) );
    }
    else
    {
        return dp[n][w] = kp(wt,val,n-1,w);
    }
}
int main()
{
    fast

    
    ll n,w;
    cin>>n>>w;
    mem(dp,-1);
    ll wt[n];
    ll val[n];
    ll st = 0;
    for(int i=0;i<n;i++)
    {
        cin>>wt[st]>>val[st];
        st++;
    }

    ll ans = kp(wt,val,n,w);
    cout<<ans<<nl;

    return 0;
}
// STAY HUNGRY, STAY FOOLISH

Measured memory_bytes: 79232