import java.util.BitSet; class Xor128 { public static final int RAND_INF = 10000000; private int x = 123456789, y = 362436069, z = 521288629, w = 88675123; public int next(int max) { return next() % max; } public int next() { int t = (x ^ (x << 11)); x = y; y = z; z = w; return (w = (w ^ (w >> 19)) ^ (t ^ (t >> 8))); } public void shuffle(int[] array) { int n = array.length; for (int i = n - 1; i >= 1; i--) { int j = next() % i; int tmp = array[i]; array[i] = array[j]; array[j] = tmp; } } } class State { public BitSet set; public long score = 0; public long w = 0; public State(int n) { this.set = new BitSet(n); } public State(State state) { this.set = new BitSet(state.set.length()); this.score = state.score; this.w = state.w; } } public class Main { private static final long TIME = 1900; private static final int R = 1000; private static void solve() { int N = ni(); long W = nl(); long[][] item = new long[N][3]; for (int i = 0; i < N; i ++) { item[i][0] = i; item[i][1] = nl(); item[i][2] = nl(); } Xor128 rand = new Xor128(); long start = System.currentTimeMillis(); long now = System.currentTimeMillis(); int count = 0; State state = new State(N); State bestState = new State(state); while (now - start <= TIME) { count ++; if (count % 100 == 0) { now = System.currentTimeMillis(); } long time = now - start; int idx = rand.next(N); long nextW = 0; long nextScore = 0; if (state.set.get(idx)) { nextW = state.w - item[idx][2]; nextScore = state.score - item[idx][1]; } else { nextW = state.w + item[idx][2]; nextScore = nextW > W ? -1 : state.score + item[idx][1]; } boolean forceNext = R * (TIME - time) > TIME * (rand.next(R)); if (nextScore > state.score || (forceNext && nextScore >= 0)) { state.set.flip(idx); state.w = nextW; state.score = nextScore; } if (state.score > bestState.score) { bestState = new State(state); } } //System.err.println(now - start + "ms"); System.out.println(bestState.score); } public static void main(String[] args) { new Thread(null, new Runnable() { @Override public void run() { long start = System.currentTimeMillis(); String debug = args.length > 0 ? args[0] : null; if (debug != null) { try { is = java.nio.file.Files.newInputStream(java.nio.file.Paths.get(debug)); } catch (Exception e) { throw new RuntimeException(e); } } reader = new java.io.BufferedReader(new java.io.InputStreamReader(is), 32768); solve(); out.flush(); tr((System.currentTimeMillis() - start) + "ms"); } }, "", 64000000).start(); } private static java.io.InputStream is = System.in; private static java.io.PrintWriter out = new java.io.PrintWriter(System.out); private static java.util.StringTokenizer tokenizer = null; private static java.io.BufferedReader reader; public static String next() { while (tokenizer == null || !tokenizer.hasMoreTokens()) { try { tokenizer = new java.util.StringTokenizer(reader.readLine()); } catch (Exception e) { throw new RuntimeException(e); } } return tokenizer.nextToken(); } private static double nd() { return Double.parseDouble(next()); } private static long nl() { return Long.parseLong(next()); } private static int[] na(int n) { int[] a = new int[n]; for (int i = 0; i < n; i++) a[i] = ni(); return a; } private static char[] ns() { return next().toCharArray(); } private static long[] nal(int n) { long[] a = new long[n]; for (int i = 0; i < n; i++) a[i] = nl(); return a; } private static int[][] ntable(int n, int m) { int[][] table = new int[n][m]; for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { table[i][j] = ni(); } } return table; } private static int[][] nlist(int n, int m) { int[][] table = new int[m][n]; for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { table[j][i] = ni(); } } return table; } private static int ni() { return Integer.parseInt(next()); } private static void tr(Object... o) { if (is != System.in) System.out.println(java.util.Arrays.deepToString(o)); } }