#include <iostream>
#include <fstream>
#include <cstdlib>
#include <climits>
#include <iomanip>
#include <set>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <iterator>
#include <vector>
#include <algorithm>
#include <numeric>
#include <queue>
#include <stack>
#include <bitset>
#include <functional>
#include <utility>
#include <cmath>
#include <string>
#include <deque>
#include <array>
#include <tuple>
#include <cstring>
#include <ctime>
#include <random>
#include <chrono>
///#include <windows.h>
#pragma GCC optimize("fast-math")
#define ll long long
#define ld long double
#define pll pair<ll, ll>
#define tll tuple<ll, ll, ll>
#define psi pair<short int, short int>
#define fir first
#define sec second
#define mp make_pair
#define pb push_back
#define all(x) (x).begin() + 1, (x).end()
#define all0(x) (x).begin(), (x).end()
#define allrev(x) (x).rbegin(), (x).rend() - 1
#define allrev0(x) (x).rbegin(), (x).rend()
#define println(thing) cout << thing << '\n'
#define yes println("YES")
#define no println("NO")
#define maybe println("MAYBE")
#define mda println("/////////////////")
#define msb(x) ((x) == 0 ? 0 : (1 << (64 - __builtin_clzll(x) - 1)))
#define lsb(x) ((x) & (-x))
using namespace std;
mt19937_64 rng(chrono :: steady_clock :: now().time_since_epoch().count());
const size_t fixed_random = rng();
clock_t start_time = clock(), end_time;
ll random_seed(ll modulo) {
return rng() % modulo;
}
template <typename T>
inline void hash_combine(size_t& seed, const T& value) {
seed ^= hash<T>{}(value) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
struct pair_hash {
template <typename T1, typename T2>
size_t operator () (const pair<T1, T2>& p) const {
size_t seed = fixed_random;
hash_combine(seed, p.first);
hash_combine(seed, p.second);
return seed;
}
};
struct normal_hash {
template <typename T>
size_t operator () (const T& p) const {
size_t seed = fixed_random;
hash_combine(seed, p);
return seed;
};
};
template <typename unordered_Map>
void optimize_map(unordered_Map& M) {
M.reserve(1024);
M.max_load_factor(0.5);
}
template <typename T1, typename T2>
istream& operator >> (istream& in, pair<T1, T2>& p) {
in >> p.first >> p.second;
return in;
}
template <typename T1, typename T2>
ostream& operator << (ostream& out, pair<T1, T2>& p) {
out << p.first << ' ' << p.second;
return out;
}
/// for bitset bits
template <typename T1, typename T2> T1 operator ^= (T1 t1, T2 t2) {t1 = t1 ^ t2; return t1;}
template <typename T1, typename T2> T1 operator |= (T1 t1, T2 t2) {t1 = t1 | t2; return t1;}
template <typename T1, typename T2> T1 operator &= (T1 t1, T2 t2) {t1 = t1 & t2; return t1;}
const ll NMX = (ll) 5001;
const ll MOD = (ll) 998244353;
const ll INF = (ll) 1e17;
ll binExp(ll base, ll exp) {
ll P = 1;
for (ll bit = 1; bit <= exp; bit <<= 1) {
if (exp & bit) {
P = (P * base) % MOD;
}
base = (base * base) % MOD;
}
return P;
}
inline ll modInv(ll x) {
return binExp(x, MOD - 2);
}
struct element {
ll w, p;
}item[NMX];
ll test_case = 0;
ll n, G, ptot, wtot, pmax;
ll psuffix[NMX + 1], wsuffix[NMX + 1];
ll normal_greedy(ll pos, ll W) {
ll cost = 0;
ll weight = 0;
for (ll i = pos; i <= n; i++) {
if (weight + item[i].w <= W) {
cost += item[i].p;
weight += item[i].w;
}
else {
break;
}
}
return cost;
}
ll partial_greedy(ll pos, ll W) {
double cost = 0;
double weight = 0;
for (ll i = pos; i <= n; i++) {
if (weight + item[i].w <= W) {
cost += item[i].p;
weight += item[i].w;
}
else {
cost += ((double) (W - weight) / item[i].w) * item[i].p;
}
}
return cost;
}
void backtrack(ll pos) {
if (pos == n + 1) {
pmax = max(pmax, ptot);
return;
}
end_time = clock();
if (end_time - start_time >= 190 * CLOCKS_PER_SEC) {
cout << pmax;
exit(0);
}
backtrack(pos + 1);
if (wtot + item[pos].w > G) {
return;
}
if (ptot + item[pos].p + psuffix[pos + 1] <= pmax) {
return;
}
if (wtot + item[pos].w + wsuffix[pos + 1] <= G) {
pmax = max(pmax, ptot + item[pos].p + psuffix[pos + 1]);
return;
}
if (ptot + item[pos].p + partial_greedy(pos + 1, G - wtot - item[pos].w) <= pmax) {
return;
}
wtot += item[pos].w;
ptot += item[pos].p;
backtrack(pos + 1);
wtot -= item[pos].w;
ptot -= item[pos].p;
return;
}
void solve(ll testcase)
{
cin >> n >> G;
for (ll i = 1; i <= n; i++) {
cin >> item[i].w >> item[i].p;
}
sort(item + 1, item + n + 1, [&](element u, element v) {
return u.p * v.w >= v.p * u.w;
});
for (ll i = n; i >= 1; i--) {
psuffix[i] = psuffix[i + 1] + item[i].p;
wsuffix[i] = wsuffix[i + 1] + item[i].w;
}
pmax = normal_greedy(1, G);
backtrack(1);
cout << pmax;
}
int main(void)
{
freopen("rucsac.in", "r", stdin);
freopen("rucsac.out", "w", stdout);
ios::sync_with_stdio(false);
cin.tie(nullptr);
///cout << fixed << setprecision(20);
///ll tt; cin >> tt; while (tt--)
solve(++test_case);
return 0;
}
/**
///
**/