//Main header file
#include <bits/stdc++.h>
using namespace std;

//For PBDS
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
template<typename T>
using ordered_set = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;
#define orderfind 		find_by_order
#define orderkey 		order_of_key

//Constants
typedef long long ll;
typedef long double ld;
const ll MOD = 1000000007;
const ll INF = 1e18;
const ll MAX = 1e6;

//Vectors
#define vl 			vector<ll>
#define vvl 		vector<vl>
#define vpl 		vector<pl>
#define vb 			vector<bool>
#define vd 			vector<ld>
#define vs 			vector<string>
#define pb 			emplace_back
//Pair
#define pl 			pair<ll, ll>
#define ff 			first
#define ss 			second
#define mp 			make_pair
//Extras
#define ql 			queue<ll>
#define sl 			stack<ll>
#define Set 		set<ll>
#define SetDesc 	set<ll, greater<ll>>
#define PQ(t)		priority_queue<t, vector <t>, greater <t>>
#define PQD(t)		priority_queue<t>
//General
#define fastio 		ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define all(a) 		a.begin(), a.end()
#define uniq(a)     (a).resize(distance((a).begin(), unique(all(a))))
#define min(a, b) 	(a<b?a:b)
#define max(a, b) 	(a>b?a:b)
#define ab(a)       (a<0)?(-1*a):a
#define mid(s,e)    (s+(e-s)/2)
#define minel(a)	*min_element(all(a))
#define maxel(a)	*max_element(all(a))
//Grid Movement
int dx[] = {-1, 0, 1, 0};
int dy[] = {0, -1, 0, 1};

//Functions 
ll mod_sum() { return 0LL; }
template<typename T, typename... Args>
T mod_sum(T a, Args... args) { return ((a + mod_sum(args...))%MOD + MOD)%MOD; }

ll mod_prod() { return 1LL; }
template<typename T, typename... Args>
T mod_prod(T a, Args... args) { return (a*mod_prod(args...))%MOD; }

ll power(ll mult, ll pow, ll mod = MOD);
ll gcd(ll a, ll b);
ll lcm(ll a, ll b);
ll inv(ll a, ll m = MOD);
void sieve(ll n);
vl primes;
vb is_prime;


ll n, W;
vl w, v;
vvl dp(105, vl(1e5+5));

ll rec(ll pos, ll weight)
{
	if(weight > W)
		return -INF;
	if(pos >= n)
		return 0;
	if (dp[pos][weight] != -1)
        return dp[pos][weight];

	return dp[pos][weight] = max(rec(pos+1, weight+w[pos])+v[pos], rec(pos+1, weight));
}

void solve()
{
	cin >> n >> W;

	w.resize(n);
	v.resize(n);

	for(int i = 0; i<n; i++)
		cin >> w[i] >> v[i];

	for(int i = 0; i<n; i++)
		for(int j = 0; j<1e5+5; j++)
			dp[i][j] = -1;

	cout << rec(0, 0) << "\n";
}


int main()
{
	fastio;

    int t = 1;
    //cin >> t;

    while(t--)
    	solve();

	return 0;
}



// Helper functions
ll power(ll mult, ll pow, ll mod)
{
	ll res = 1;
	while(pow > 0)
	{
		if(pow&1)
		{
			res *= mult;
			res %= mod;
		}
		mult *= mult;
		mult %= mod;
		pow >>=  1;
	}
	return res;
}

ll gcd(ll a, ll b)
{
	if(b == 0)
		return a;
	return gcd(b, a%b);
}

ll lcm(ll a, ll b)
{
	return (a*b)/gcd(a, b);
}

void sieve(ll n)
{
	is_prime.resize(n+1);
	primes.resize(n+1);

	is_prime[0] = is_prime[1] = false;
	for(int i = 2; i<=n; i++)
	{
	    if(is_prime[i])
	    {
	    	primes.pb(i);
	        for (int j = i*i; j<=n; j+=i)
	            is_prime[j] = false;
	    }
	}
}


ll inv(ll a, ll m)
{
    ll m0 = m;
    ll y = 0, x = 1;

    if (m == 1)
      return 0;

    while (a > 1)
    {
        int q = a / m;
        int t = m;
        m = a % m, a = t;
        t = y;
        y = x - q * y;
        x = t;
    }

    if (x < 0)
       x += m0;

    return x;
}

Measured memory_bytes: 83328