#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;
}
