#include using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int N; long long W; if (!(cin >> N >> W)) return 0; const int MAXW = 500; // 重さごとに最大価値を残す vector bestV(MAXW + 1, 0); for (int i = 0; i < N; ++i) { int v, w; cin >> v >> w; if (v > bestV[w]) bestV[w] = v; } // 支配される品物を削る(重さ昇順で価値が前より大きいものだけ残す) vector> items; // (w, v) int maxv = 0; for (int w = 1; w <= MAXW; ++w) { int v = bestV[w]; if (v > 0 && v > maxv) { items.emplace_back(w, v); maxv = v; } } if (items.empty()) { cout << 0 << '\n'; return 0; } // w_max(全品物の最大重さ) int w_max = 0; for (auto &p : items) w_max = max(w_max, p.first); // 価値密度が最大の品物(同率なら重さが小さい方) int w_best = items[0].first; int v_best = items[0].second; for (auto &p : items) { int w = p.first; int v = p.second; long long lhs = 1LL * v * w_best; long long rhs = 1LL * v_best * w; if (lhs > rhs || (lhs == rhs && w < w_best)) { w_best = w; v_best = v; } } long long Lll = 1LL * w_best * w_max; // L = w_best * w_max <= 250000 int B = (int)min(W, Lll); // DP する最大重さ const long long NEG = -(1LL << 60); vector dp(B + 1, NEG); dp[0] = 0; // 完全ナップサック DP(重さ 0..B) for (auto &p : items) { int wi = p.first; int vi = p.second; for (int w = wi; w <= B; ++w) { if (dp[w - wi] == NEG) continue; long long cand = dp[w - wi] + vi; if (cand > dp[w]) dp[w] = cand; } } long long ans = 0; if (W <= B) { // 容量が小さいときは普通に dp[0..W] を見る for (int w = 0; w <= (int)W; ++w) { if (dp[w] == NEG) continue; if (dp[w] > ans) ans = dp[w]; } } else { // 容量が大きいときは補題を使って「base + 最優品」で詰める for (int s = 0; s <= B; ++s) { if (dp[s] == NEG) continue; long long extra = (W - s) / w_best; long long val = dp[s] + extra * (long long)v_best; if (val > ans) ans = val; } } cout << ans << '\n'; return 0; }