#pragma GCC target("prefer-vector-width=512") #pragma GCC optimize("Ofast") #pragma GCC optimize("Ofast,unroll-loops") #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; #include #include #include #include namespace fastio { #ifndef FAST_IO #define FAST_IO #endif struct Pre { char num[10000][4]; constexpr Pre() : num() { for (int i = 0; i < 10000; i++) { int n = i; for (int j = 3; j >= 0; j--) { num[i][j] = n % 10 | '0'; n /= 10; } } } } constexpr pre; static constexpr int BUF_SZ = 1 << 18; char *ibuf, obuf[BUF_SZ], outs[100]; int outi, obufi; void __attribute__((constructor)) _c() { struct stat sb; fstat(0, &sb); ibuf = (char *)mmap(0, sb.st_size, PROT_READ, MAP_SHARED /*| MAP_POPULATE*/, 0, 0); } void flush() { write(1, obuf, obufi), obufi = 0; } void input(char &c) { c = *ibuf++; } void input(string &x) { x.clear(); char c; do { input(c); } while (isspace(c)); do { x += c, input(c); } while (!isspace(c)); } template void input_integer(T &x) { char c; do { input(c); } while (c < '-'); bool minus = 0; if constexpr (is_signed::value || is_same_v) { if (c == '-') { minus = 1, input(c); } } x = 0; while (c >= '0') { x = x * 10 + (c & 15), input(c); } if constexpr (is_signed::value || is_same_v) { if (minus) { x = -x; } } } template void input_real(T &x) { string s; input(s); x = stod(s); } void input(int &x) { input_integer(x); } void input(long long &x) { input_integer(x); } void input(__int128 &x) { input_integer(x); } void input(uint32_t &x) { input_integer(x); } void input(uint64_t &x) { input_integer(x); } void input(unsigned __int128 &x) { input_integer(x); } void input(double &x) { input_real(x); } template void input(vector &x) { for (auto &d : x) input(d); } template void input(array &x) { for (auto &d : x) input(d); } template void input(pair &p) { input(p.first), input(p.second); } template void input_tuple(T &t) { if constexpr (N < std::tuple_size::value) { auto &x = std::get(t); input(x); input_tuple(t); } } template void input(tuple &tpl) { input_tuple(tpl); } void in() {} template void in(H &h, T &... t) { input(h), in(t...); } void output(const char c) { if (obufi == BUF_SZ) flush(); obuf[obufi++] = c; } void output(const string &s) { for (char c : s) output(c); } template void output_integer(T x) { if (obufi > BUF_SZ - 100) flush(); if (x < 0) { obuf[obufi++] = '-', x = -x; } for (outi = 96; x >= 10000; outi -= 4) { memcpy(outs + outi, pre.num[x % 10000], 4); x /= 10000; } if (x >= 1000) { memcpy(obuf + obufi, pre.num[x], 4); obufi += 4; } else if (x >= 100) { memcpy(obuf + obufi, pre.num[x] + 1, 3); obufi += 3; } else if(x >= 10) { int q = (x * 103) >> 10; obuf[obufi] = q | '0'; obuf[obufi + 1] = (x - q * 10) | '0'; obufi += 2; } else { obuf[obufi++] = x | '0'; } memcpy(obuf + obufi, outs + outi + 4, 96 - outi); obufi += 96 - outi; } template void output_real(T x) { ostringstream oss; oss << fixed << setprecision(15) << double(x); string s = oss.str(); output(s); } void output(int x) { output_integer(x); } void output(long long x) { output_integer(x); } void output(__int128 x) { output_integer(x); } void output(uint32_t x) { output_integer(x); } void output(uint64_t x) { output_integer(x); } void output(unsigned __int128 x) { output_integer(x); } void output(double x) { output_real(x); } void output(long double x) { output_real(x); } template void output(const vector &val) { size_t n = val.size(); for (size_t i = 0; i < n; i++) { if (i) output(' '); output(val[i]); } } template void output(const pair &val) { output(val.first); output(' '); output(val.second); } template void output_tuple(const T &t) { if constexpr (N < std::tuple_size::value) { if constexpr (N > 0) { output(' '); } const auto x = std::get(t); output(x); output_tuple(t); } } template void output(tuple &tpl) { output_tuple(tpl); } template void output(const array &val) { size_t n = val.size(); for (size_t i = 0; i < n; i++) { if (i) output(' '); output(val[i]); } } void out() { output('\n'); } template void out(H &&h, T &&... t) { output(h); if (sizeof...(T)) output(sep); out(t...); } void outr() {} template void outr(H &&h, T &&... t) { output(h); outr(t...); } void __attribute__((destructor)) _d() { flush(); } } // namespace fastio using fastio::in; using fastio::out; using ll = long long; constexpr ll INF = 1e18; int coef[1000], vi[20], wi[20]; ll dp[1000], f[1000], aux1[1000], aux2[1000]; int main() { int n, m; in(n, m); for (int i = 0; i < n; i++) { in(vi[i], wi[i]); coef[1000 - wi[i]] = max(coef[1000 - wi[i]], vi[i]); } for (int x = 1; x < 1000; x++) { for (int i = 0; i < n; i++) { if (x >= wi[i]) dp[x] = max(dp[x], dp[x - wi[i]] + vi[i]); } } fill_n(f, 1000, -INF); f[0] = 0; int p = 31 - __builtin_clz(m); while (p >= 0) { memcpy(aux1, f, sizeof(ll) * 1000); memcpy(aux2, f, sizeof(ll) * 1000); for (int i = 0; i < 1000; i++) f[i] = aux1[0] + aux2[i]; for (int i = 1; i < 1000; i++) { ll bk = aux2[999]; for (int j = 999; j >= 1; j--) aux2[j] = max(aux2[j - 1], bk + coef[j]); aux2[0] = bk + coef[0]; for (int j = 0; j < 1000; j++) f[j] = max(f[j], aux1[i] + aux2[j]); } if (m >> p & 1) { ll bk = f[999]; for (int i = 999; i >= 1; i--) f[i] = max(f[i - 1], bk + coef[i]); f[0] = bk + coef[0]; } p--; } ll ans = 0; for (int i = 0; i < 1000; i++) ans = max(ans, f[i] + dp[i]); out(ans); }