제출 #1291854

#제출 시각아이디문제언어결과실행 시간메모리
1291854atharva0300Knapsack (NOI18_knapsack)C++20
73 / 100
372 ms327680 KiB
#include <bits/stdc++.h>
using namespace std;

/*
  NOI 2018 - Knapsack (Task 2)

  Complexity:
    - Let S <= 2000.
    - Grouping and sorting per weight: O(T log T), T = total truncated copies = O(S log S).
    - DP: O(T * S) ~ O(S^2 log S).
    - Memory: O(S).
*/

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int S, N;
    if (!(cin >> S >> N)) {
        return 0;
    }

    // group[w] holds values of items of weight w (with multiplicities,
    // but we will truncate later).
    vector<vector<long long>> group(S + 1);

    for (int i = 0; i < N; ++i) {
        long long V;
        int W;
        long long K;
        cin >> V >> W >> K;
        if (W > S) continue; // can never be taken

        // Maximum useful copies of this item by capacity:
        long long max_copies = S / W;
        if (max_copies == 0) continue;

        long long take = min(K, max_copies);

        // Instead of doing binary splitting, just push 'take' copies of V
        // into group[W]; we'll truncate after merging all items of weight W.
        // Since we will finally keep at most floor(S / W) total values for this weight,
        // this push may overfill but truncation will fix it.
        // However, to avoid pathological overpush when many items share same weight,
        // we can cap per item too:
        if (take > 0) {
            // But we still must be careful of large 'take' (up to 2000).
            // It is fine to push directly since S<=2000.
            for (long long c = 0; c < take; ++c) {
                group[W].push_back(V);
            }
        }
    }

    // For each weight, keep only the best floor(S / w) values.
    for (int w = 1; w <= S; ++w) {
        if (group[w].empty()) continue;
        int limit = S / w;
        if ((int)group[w].size() > limit) {
            // partial sort to get top 'limit' values
            nth_element(group[w].begin(), group[w].begin() + limit, group[w].end(),
                        greater<long long>());
            group[w].resize(limit);
        }
    }

    // 1D 0/1 knapsack DP
    vector<long long> dp(S + 1, 0);

    for (int w = 1; w <= S; ++w) {
        if (group[w].empty()) continue;
        // For each copy as a separate 0/1 item
        for (long long v : group[w]) {
            // standard 0/1 knapsack transition, descending over weight
            for (int curW = S; curW >= w; --curW) {
                long long cand = dp[curW - w] + v;
                if (cand > dp[curW]) dp[curW] = cand;
            }
        }
    }

    long long ans = 0;
    for (int w = 0; w <= S; ++w) {
        if (dp[w] > ans) ans = dp[w];
    }

    cout << ans << '\n';
    return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...