// Original C++ solution (slower):
#include <bits/stdc++.h>

#include <ext/pb_ds/assoc_container.hpp>

#include <ext/pb_ds/tree_policy.hpp>



using namespace std;

using namespace __gnu_pbds;



#define fi first

#define se second

#define mp make_pair

#define pb push_back

#define fbo find_by_order

#define ook order_of_key



typedef long long ll;

typedef pair<ll,ll> ii;

typedef vector<ll> vi;

typedef long double ld; 

typedef tree<int, null_type, less<int>, rb_tree_tag, tree_order_statistics_node_update> pbds;

typedef set<int>::iterator sit;

typedef map<int,int>::iterator mit;

typedef vector<int>::iterator vit;



ll a[101];

ll b[101];

ll dp[4][301][101];

ll sum[4][101];



int main()

{

	ios_base::sync_with_stdio(0); cin.tie(0);

	ll n; ll w;

	cin>>n>>w;

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

	{

		cin>>a[i]>>b[i];

	}

	ll ans=0;

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

	{

		vector<ll> vec[4];

		memset(dp,0,sizeof(dp));

		memset(sum,0,sizeof(sum));

		ll ww = w-ll(i)*a[0];

		ww=min(ww,3LL*i);

		if(ww<0) continue;

		for(int j=0;j<n;j++)

		{

			vec[a[j]-a[0]].pb(b[j]);

		}

		for(int j=0;j<4;j++) sort(vec[j].rbegin(),vec[j].rend());

		for(int j=0;j<4;j++)

		{

			for(int k=0;k<vec[j].size();k++)

			{

				sum[j][k]=vec[j][k];

				if(k>0) sum[j][k]+=sum[j][k-1];

			}

		}

		for(int j=0;j<vec[0].size();j++)

		{

			dp[0][0][j+1] = sum[0][j];

		}

		for(int j=0;j<3;j++)

		{

			for(int k=0;k<=ww;k++)

			{

				for(int l=0;l<=i;l++)

				{

					//cerr<<j<<' '<<k<<' '<<l<<' '<<dp[j][k][l]<<'\n';

					ll val = dp[j][k][l];

					dp[j+1][k][l]=max(dp[j+1][k][l],val);

					for(int m=0;m<vec[j+1].size();m++)

					{

						if(l+m+1<=i&&k+(j+1)*(m+1)<=ww)

						{

							dp[j+1][k+(j+1)*(m+1)][l+m+1]=max(dp[j+1][k+(j+1)*(m+1)][l+m+1],val+sum[j+1][m]);

						}

					}

				}

			}

		}

		ll an=0;

		for(int k=0;k<=ww;k++)

		{

			an=max(an,dp[3][k][i]);

		}

		//cerr<<i<<' '<<ww<<' '<<an<<'\n';

		ans=max(ans,an);

	}

	cout<<ans<<'\n';

}


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

#include<algorithm> 

#include<cstdio>  

#include<cstring>    

using namespace std;  

int n,m,a,b,c,d;

long long sum,ans; 

struct node  

{  

    int w,v;  

}g[110];  

  

bool cmp(node a,node b)  

{  

    return a.v>b.v;  

}  

node A[110],B[110],C[110],D[110];  

  

long long swa[110],swb[110],swc[110],swd[110];  

long long sva[110],svb[110],svc[110],svd[110]; 

  

int main()  

{  

        cin>>n>>m; 

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

        {  

            cin>>g[i].w>>g[i].v;  

            if(g[i].w==g[1].w) A[++a]=g[i];  

            if(g[i].w==g[1].w+1) B[++b]=g[i];  

            if(g[i].w==g[1].w+2) C[++c]=g[i];  

            if(g[i].w==g[1].w+3) D[++d]=g[i];  

        }  

        sort(A+1,A+a+1,cmp);  

        sort(B+1,B+b+1,cmp);  

        sort(C+1,C+c+1,cmp);  

        sort(D+1,D+d+1,cmp);  

        

        for(int i=1;i<=a;i++)  

        {  

            swa[i]=swa[i-1]+A[i].w;  

            sva[i]=sva[i-1]+A[i].v;  

        }  

        for(int i=1;i<=b;i++)  

        {  

            swb[i]=swb[i-1]+B[i].w;  

            svb[i]=svb[i-1]+B[i].v;  

        }  

        for(int i=1;i<=c;i++)  

        {  

            swc[i]=swc[i-1]+C[i].w;  

            svc[i]=svc[i-1]+C[i].v;  

        }  

        for(int i=1;i<=d;i++)  

        {  

            swd[i]=swd[i-1]+D[i].w;  

            svd[i]=svd[i-1]+D[i].v;  

        }  

    

        for(int i=0;i<=a;i++)  

        for(int j=0;j<=b;j++)  

        for(int k=0;k<=c;k++)  

        for(int l=0;l<=d;l++)  

        {  

        sum=swa[i]+swb[j]+swc[k]+swd[l];  

        if(sum<=m)  

        ans=max(ans,sva[i]+svb[j]+svc[k]+svd[l]);  

              

        }  

        cout<<ans<<endl;  

    

  

    return 0;  

}  

// Fastest known solution for this problem: