#include <algorithm>
#include <fstream>
#include <cstring>
#include <vector>
#include <cmath>
#include <limits.h>
#include <iostream>
using namespace std;
#define MAXN 5005;
#define MAXW 1000016
#define INF 0x3f3f3f3f
#define LLINF 0x3f3f3f3f3f3f3f3f
template<typename T> void maximize(T &res, const T &val) { if (res < val) res = val; }
template<typename T> void minimize(T &res, const T &val) { if (res > val) res = val; }
ifstream fin("rucsac.in");
ofstream fout("rucsac.out");
long long n, w, val;
long long c[MAXW], v[MAXW];
long long f[MAXW];
long long f2[MAXW];
long long auxv[MAXW];
vector<int> selected;
void ReadData() {
fin >> n >> w;
for (int i = 1; i <= n; ++i) {
fin >> c[i] >> v[i];
}
}
namespace weights {
int calc(long long *f, int l = 1, int r = n)
{
long long upper = 0;
for (int i = l; i <= r; ++i)
upper += c[i];
minimize(upper, (long long)w);
for (int s = 0; s <= upper; ++s)
f[s] = 0;
for (int i = l; i <= r; ++i)
for (int s = upper; s >= c[i]; --s)
maximize(f[s], f[s - c[i]] + v[i]);
return upper;
}
void trace(int s = w, int l = 1, int r = n)
{
if (l == r)
{
if (s == c[l])
{
selected.push_back(l);
}
return ;
}
int m = (l + r) >> 1;
int sleft = calc(f, l, m + 0);
int sright = calc(f2, m + 1, r);
long long mx = -1;
int pleft = 0;
int pright = s;
for (int v = max(0, s - sright); v <= min(s, sleft); ++v)
{
if (mx < f[v] + f2[s - v])
{
mx = f[v] + f2[s - v];
pleft = v;
pright = s - v;
}
}
trace(pleft , l, m + 0);
trace(pright, m + 1, r);
}
void solve() {
weights::calc(f);
long long res = f[w];
int weight_used = max_element(f, f + w + 1) - f;
weights::trace(weight_used);
fout << res << '\n';
for (int p : selected) {
fout << c[p] << ' ' << v[p] << '\n';
}
}
} // namespace weights
namespace values {
int calc(long long *values, long long *f, int l = 1, int r = n)
{
f[0] = 0;
for (int s = val; s >= 1; --s)
f[s] = +LLINF;
for (int i = l; i <= r; ++i)
for (int s = val; s >= values[i]; --s)
minimize(f[s], f[s - values[i]] + c[i]);
return val;
}
void trace(long long *values, int s = MAXW, int l = 1, int r = n)
{
if (l == r)
{
if (s == values[l])
{
selected.push_back(l);
}
return ;
}
int m = (l + r) >> 1;
int sleft = calc(values, f, l, m + 0);
int sright = calc(values, f2, m + 1, r);
int mn = +INF;
int pleft = 0;
int pright = s;
for (int v = max(0, s - sright); v <= min(s, sleft); ++v)
{
if (mn > f[v] + f2[s - v])
{
mn = f[v] + f2[s - v];
pleft = v;
pright = s - v;
}
}
trace(values, pleft , l, m + 0);
trace(values, pright, m + 1, r);
}
void solve() {
int res = calc(v, f);
while (f[res] > w) --res;
trace(v, res);
int ans = 0;
for (int p : selected)
ans += v[p];
fout << ans << '\n';
for (int p : selected)
{
fout << c[p] << ' ' << v[p] << '\n';
}
}
} // namespace values
namespace fptas {
double invlerp(long long a, long long b, long long v) {
return (double)(v - a) / (b - a);
}
void compress(double eps) {
long long maxProfit = 0;
for (int i = 1; i <= n; i++) {
maxProfit = max(maxProfit, v[i]);
}
double scalingFactor = eps * maxProfit / n;
for (int i = 1; i <= n; i++) {
auxv[i] = v[i] / scalingFactor;
}
}
void solve() {
compress(invlerp(MAXW - 5, LLONG_MAX, val) / 1.5);
for (int i = 1; i <= n; ++i)
val += auxv[i];
int res = values::calc(auxv, f);
while (f[res] > w) --res;
values::trace(auxv, res);
int ans = 0;
for (int p : selected)
ans += v[p];
fout << ans << '\n';
for (int p : selected)
{
fout << c[p] << ' ' << v[p] << '\n';
}
}
} // namespace brute
int main()
{
ReadData();
if (w <= MAXW - 5) {
weights::solve();
} else {
for (int i = 1; i <= n; ++i) {
long long term = v[i] * (c[i] <= w);
if (val + term < 0) {
val = LLONG_MAX;
fptas::solve();
}
val += term;
}
if (val <= MAXW - 5) {
values::solve();
}
else {
fptas::solve();
}
}
return 0;
}