結果

問題 No.3401 Large Knapsack Problem
コンテスト
ユーザー sclara
提出日時 2025-11-27 13:25:47
言語 C++23
(gcc 13.3.0 + boost 1.89.0)
結果
RE  
実行時間 -
コード長 2,576 bytes
記録
記録タグの例:
初AC ショートコード 純ショートコード 純主流ショートコード 最速実行時間
コンパイル時間 3,085 ms
コンパイル使用メモリ 283,920 KB
実行使用メモリ 7,848 KB
最終ジャッジ日時 2025-12-07 23:30:19
合計ジャッジ時間 4,746 ms
ジャッジサーバーID
(参考情報)
judge1 / judge2
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 3
other AC * 37 WA * 3 RE * 2
権限があれば一括ダウンロードができます

ソースコード

diff #
raw source code

#include <bits/stdc++.h>
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<int> 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<pair<int,int>> 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<long long> 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;
}
0