#include <bits/stdc++.h>
#include <windows.h>
#include <psapi.h>
#pragma comment(lib,"psapi.lib")
#define ll long long
#define db double
#define ldb long double
#define lp(i, j, n) for(int i = j; i <= n; ++i)
#define dlp(i, n, j) for(int i = n; i >= j; --i)
#define mst(n, v) memset(n, v, sizeof(n))
#define mcy(n, v) memcpy(n, v, sizeof(v))
#define INF 1e18
#define MAX4 0x3f3f3f3f
#define MAX8 0x3f3f3f3f3f3f3f3f
#define pii pair<int, int>
#define pll pair<ll, ll>
#define co(x) cout << (x) << ' '
#define cod(x) cout << (x) << endl
#define lc(x) ((x) << 1)
#define rc(x) ((x) << 1 ^ 1)
#define ls ch[x][0]
#define rs ch[x][1]
#define fi first
#define se second
#define pb(x) emplace_back(x)
using namespace std;
const int N = 23, M = 12;
const ll MOD = 998244353;
struct node {
int sum, num, cst;
bool operator < (const node & t) const { return sum < t.sum; }
};
struct ipt { int a, b; } tmp[N];
int n, m, a[N], b[N], L, R;
int rsm[1 << M], lsm[1 << M];
int f[2][1 << M], g[2][1 << N];
node h[1 << M][1 << M]; int hn[1 << M];
/*
f[0/1][s]: 右边最小代价和方案数
h[s]: 为 s 时左边与(右边所有子集)按 sum{a} 排序后的代价前缀最小值,和对应方案数
g[0/1][s]: 为 s 时全局最小代价和方案数
lsm[s]: 左边为 s 时 a[i] 和
rsm[s]: 右边为 s 时 a[i] 和
*/
signed main() {
// freopen(".in", "r", stdin);
// freopen(".out", "w", stdout);
#ifndef READ
ios::sync_with_stdio(false);
cin.tie(0);
#endif
cin >> n >> m;
lp(i, 1, n) cin >> tmp[i].a >> tmp[i].b;
sort(tmp + 1, tmp + 1 + n, [&] (ipt t1, ipt t2) { return t1.b > t2.b; });
lp(i, 1, n) a[i] = tmp[i].a, b[i] = tmp[i].b;
L = n / 2, R = n - L;
mst(f[0], 0x3f), mst(g[0], 0x3f), f[0][0] = 0, f[1][0] = 1;
lp(s, 0, (1 << R) - 1) {
lp(i, 1, R) rsm[s] += 1 << i - 1 & s ? a[L + i] : 0;
for(int i = s; i; i = s & i - 1) { // 转移 f
if(rsm[i] <= m && (s & -s) == (i & -i)) {
ll v = f[0][s ^ i] + b[L + (int)log2(i & -i) + 1];
if(v < f[0][s]) f[0][s] = v, f[1][s] = f[1][s ^ i];
else if(v == f[0][s]) (f[1][s] += f[1][s ^ i]) %= MOD;
}
}
// co(s), cod(f[0][s]);
g[0][s << L] = f[0][s], g[1][s << L] = f[1][s];
}
// co(f[0][(1 << R) - 1]), cod(f[1][(1 << R) - 1]);
lp(s, 0, (1 << L) - 1) lp(i, 1, L) lsm[s] += 1 << i - 1 & s ? a[i] : 0;
lp(s2, 0, (1 << R) - 1) { // 枚举右边
// cod(s2);
// if(s2 % 100 == 0) {
// cout << 1 << endl;
// }
lp(s, 0, (1 << L) - 1) { // 枚举左边
ll S = s2 << L | s;
for(int i = s; i; i = s & i - 1) { // 枚举左边子集并转移 g
if(lsm[i] <= m && (s & -s) == (i & -i)) {
auto t = upper_bound(h[s ^ i] + 1, h[s ^ i] + 1 + hn[s ^ i], (node) { m - lsm[i], 0ll, 0ll }) - 1;
ll v = t->cst + b[(int)log2(i & -i) + 1];
// co(t->sum), co(t->cst), cod(t->num);
// co(v), co(g[0][S]), cod(t->num);
if(v < g[0][S]) g[0][S] = v, g[1][S] = t->num;
else if(v == g[0][S]) (g[1][S] += t->num) %= MOD;
}
}
// co(S), co(s), co(s2), co(g[0][S]), cod(g[1][S]);
for(int i = s2; ; i = s2 & i - 1) { // 处理 h
if(rsm[i] <= m) {
h[s][++hn[s]] = { rsm[i], g[1][S ^ (i << L)], g[0][S ^ (i << L)] };
// co(rsm[i]), co(g[1][S ^ (i << L)]), cod(g[0][S ^ (i << L)]);
}
if(!i) break;
}
sort(h[s] + 1, h[s] + 1 + hn[s]);
lp(i, 2, hn[s]) { // 做代价前缀最小值并计算方案数前缀和
if(h[s][i].cst > h[s][i - 1].cst) h[s][i].cst = h[s][i - 1].cst, h[s][i].num = h[s][i - 1].num;
else if(h[s][i].cst == h[s][i - 1].cst) (h[s][i].num += h[s][i - 1].num) %= MOD;
}
}
lp(s, 0, (1 << L) - 1) { lp(i, 1, hn[s]) h[s][i] = { 0, 0, 0 }; hn[s] = 0; }
}
cout << g[0][(1 << n) - 1] << ' ' << g[1][(1 << n) - 1] % MOD << endl;
// HANDLE handle = GetCurrentProcess();
// PROCESS_MEMORY_COUNTERS pmc;
// GetProcessMemoryInfo(handle, &pmc, sizeof(pmc));
// printf("%d\r\n", pmc.WorkingSetSize / 1000); //结果保存单位是B,可以除以1000保存为kb格式
return 0;
}