#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cstdlib>
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100,MAX_V=1005,INF=0x3f3f3f3f;
int n=4,m,vis[15],V;
typedef long long LL;
typedef pair<int,int> P;
LL ans;
LL rv,cw,C,x[100],cv;
struct node{
int w,v;
node(int a,int b){ w=a; v=b;}
bool operator < (node& x){//将物品按重量从小到大分组,每组中价值大的放前面
return w<x.w||(w==x.w&&v>x.v);
}
};
vector<node> N;
void dfs(int i,int bound){ //搜索,bound为取物品的标准
if (i>=n){
ans=max(ans,cv);
return ;
}
rv-=N[i].v; //当前最多能取得的价值
if (cw+N[i].w<=C&&N[i].v>bound){ //如果不超重且这组物品的价值比bound大,取之
x[i]=1;cw+=N[i].w;cv+=N[i].v;
dfs(i+1,bound);
cw-=N[i].w;cv-=N[i].v;
}
if (cv+rv>ans){ //未来取到的价值有可能比当前解更优
x[i]=0;
dfs(i+1,max(N[i].v,bound)); //不取当前物品,更新bound,可以这样考虑,在当前重量下都不取该物品,
//则同组的其他物品不会比它更好,而后面的物品价值若比它还低,也没有取的必要,那么不如
// 把这个空间留给性价比更高的物品
}
rv+=N[i].v;
}
int main(){
scanf("%d%d",&n,&C);
for (int i=0;i<n;i++){
int v,w;
scanf("%d%d",&w,&v);
rv+=v;
N.push_back(node(w,v));
}
sort(N.begin(),N.end());
dfs(0,0);
printf("%lld\n",ans);
}