#include <bits/stdc++.h>   using namespace std;   long long gcd(long long a, long long b) { return b == 0 ? a : gcd(b, a % b); }   const int MAXN = 100000;   const int MAXCAP = 300000;   typedef struct R {     int w, c;   } R;   bool operator<(const R &a, const R &b) {     return (long long)a.c * b.w > (long long)b.c * a.w;   }   int n, cap;   R r[MAXN];   multiset<int> have[4];   multiset<int> avail[4];   long long getlargest(multiset<int> &a, int cnt) {     if (((int)(a).size()) < cnt) return INT_MIN;     auto it = a.end();     long long ret = 0;     for (int i = (0); i < (cnt); ++i) {       --it;       ret += *it;     }     return ret;   }   long long getsmallest(multiset<int> &a, int cnt) {     if (((int)(a).size()) < cnt) return INT_MAX;     auto it = a.begin();     long long ret = 0;     for (int i = (0); i < (cnt); ++i) {       ret += *it;       ++it;     }     return ret;   }   void removeone(multiset<int> &a, int val) {     auto it = a.find(val);     if (it == a.end())       printf( err (%d) n , val);     else       a.erase(it);   }   void take(int cnt, int type) {     for (int i = (0); i < (cnt); ++i) {       long long cur = getlargest(avail[type], 1);       removeone(avail[type], cur);       have[type].insert(cur);     }   }   void remove(int cnt, int type) {     for (int i = (0); i < (cnt); ++i) {       long long cur = getsmallest(have[type], 1);       removeone(have[type], cur);       avail[type].insert(cur);     }   }   void run() {     scanf( %d%d , &n, &cap);     for (int i = (0); i < (n); ++i) scanf( %d%d , &r[i].w, &r[i].c);     sort(r, r + n);     int left = cap;     for (int i = (0); i < (4); ++i) have[i].clear(), avail[i].clear();     for (int i = (0); i < (n); ++i) avail[r[i].w].insert(r[i].c);     long long ret = 0;     for (int i = (0); i < (n); ++i) {       if (r[i].w > left) break;       left -= r[i].w;       ret += r[i].c;       have[r[i].w].insert(r[i].c);       removeone(avail[r[i].w], r[i].c);     }     while (left >= 1) {       long long best = 0;       int besttype = -1;       {         long long cur = getlargest(avail[1], 1);         if (cur > best) best = cur, besttype = 0;       }       {         long long cur = getlargest(avail[2], 1) - getsmallest(have[1], 1);         if (cur > best) best = cur, besttype = 1;       }       {         long long cur = getlargest(avail[2], 2) - getsmallest(have[3], 1);         if (cur > best) best = cur, besttype = 2;       }       {         long long cur = getlargest(avail[3], 1) - getsmallest(have[2], 1);         if (cur > best) best = cur, besttype = 3;       }       {         long long cur = getlargest(avail[3], 1) - getsmallest(have[1], 2);         if (cur > best) best = cur, besttype = 4;       }       if (besttype == -1) break;       if (besttype == 0)         take(1, 1);       else if (besttype == 1)         take(1, 2), remove(1, 1);       else if (besttype == 2)         take(2, 2), remove(1, 3);       else if (besttype == 3)         take(1, 3), remove(1, 2);       else if (besttype == 4)         take(1, 3), remove(2, 1);       ret += best;       --left;     }     while (left >= 2) {       long long best = 0;       int besttype = -1;       {         long long cur = getlargest(avail[2], 1);         if (cur > best) best = cur, besttype = 0;       }       {         long long cur = getlargest(avail[3], 1) - getsmallest(have[1], 1);         if (cur > best) best = cur, besttype = 1;       }       {         long long cur = getlargest(avail[3], 2) - getsmallest(have[2], 2);         if (cur > best) best = cur, besttype = 2;       }       if (besttype == -1) break;       if (besttype == 0)         take(1, 2);       else if (besttype == 1)         take(1, 3), remove(1, 1);       else if (besttype == 2)         take(2, 3), remove(2, 2);       ret += best;       --left;     }     printf( %lld n , ret);   }   int main() {     run();     return 0;   }