제출 #1339565

#제출 시각아이디문제언어결과실행 시간메모리
1339565lucas110550축제 (IOI25_festival)C++20
48 / 100
189 ms103708 KiB
#include <bits/stdc++.h>
using namespace std;

// -------------------------------------------------------------------
// Helper structure for a booster (T > 1)
// -------------------------------------------------------------------
struct Booster {
    double a;          // sorting key: a = P * T / (T-1)
    int price;         // P[i]
    int type;          // T[i]   (used later for the token update)
    int idx;           // original coupon index
};

vector<int> max_coupons(int A,
                        vector<int> P,
                        vector<int> T)
{
    const int n = static_cast<int>(P.size());

    // -----------------------------------------------------------------
    // 1) split coupons into boosters (T>1) and cheap coupons (T==1)
    // -----------------------------------------------------------------
    vector<Booster> boosters;
    vector<pair<int,int>> cheap;               // (price , original_index)

    for (int i = 0; i < n; ++i) {
        if (T[i] == 1) {
            cheap.emplace_back(P[i], i);
        } else {
            double a_val = static_cast<double>(P[i]) * T[i] /
                           (T[i] - 1);
            boosters.push_back({a_val, P[i], T[i], i});
        }
    }

    // -----------------------------------------------------------------
    // 2) sort the two groups
    // -----------------------------------------------------------------
    sort(boosters.begin(), boosters.end(),
         [](const Booster& x, const Booster& y) { return x.a < y.a; });

    sort(cheap.begin(), cheap.end(),
         [](const pair<int,int>& x, const pair<int,int>& y) {
             return x.first < y.first;               // sort by price
         });

    // cheap_prefix[k] = sum of the k cheapest cheap coupons
    // cheap_prefix has length cheap.size() + 1, cheap_prefix[0] == 0
    vector<long long> cheap_prefix;
    cheap_prefix.reserve(cheap.size() + 1);
    cheap_prefix.push_back(0);
    for (auto &c : cheap) {
        cheap_prefix.push_back(cheap_prefix.back() + static_cast<long long>(c.first));
    }

    // -----------------------------------------------------------------
    // 3) DP over boosters, keeping only non‑dominated states
    // -----------------------------------------------------------------
    // DP vectors – they are indexed by the *state id* (its position in the vectors)
    vector<long long> tokens;   // tokens after the state
    vector<int>       cnts;     // number of boosters taken to reach the state
    vector<int>       prevs;    // previous state id ( -1 for the start state )
    vector<int>       idxs;     // original coupon index that created the state

    // start state (state id = 0)
    tokens.push_back(A);   // we start with A tokens
    cnts.push_back(0);
    prevs.push_back(-1);
    idxs.push_back(-1);   // sentinel

    // frontier = list of state ids that are currently non‑dominated
    vector<int> frontier = {0};

    // iterate over boosters in increasing a‑value
    for (const Booster& B : boosters) {
        vector<int> new_state_ids;

        // try to take this booster from every state that is currently reachable
        for (int sid : frontier) {
            if (tokens[sid] >= B.price) {               // we can afford the price
                long long new_tok = (tokens[sid] - B.price) * B.type;

                // create a new DP state
                tokens.push_back(new_tok);
                cnts.push_back(cnts[sid] + 1);
                prevs.push_back(sid);
                idxs.push_back(B.idx);
                new_state_ids.push_back(static_cast<int>(tokens.size()) - 1);
            }
        }

        // -------------------------------------------------------------
        // Merge old frontier and new states, then keep only non‑dominated
        // -------------------------------------------------------------
        vector<int> candidates = frontier;
        candidates.insert(candidates.end(), new_state_ids.begin(),
                                 new_state_ids.end());

        // sort by decreasing tokens, then decreasing cnt (exactly as in Python)
        sort(candidates.begin(), candidates.end(),
             [&](int s1, int s2) {
                 if (tokens[s1] != tokens[s2]) return tokens[s1] > tokens[s2];
                 return cnts[s1] > cnts[s2];
             });

        // keep states that are *strictly* better in cnt than any previously kept
        vector<int> new_frontier;
        int best_cnt = -1;
        for (int sid : candidates) {
            if (cnts[sid] > best_cnt) {
                new_frontier.push_back(sid);
                best_cnt = cnts[sid];
            }
        }
        frontier.swap(new_frontier);
    }

    // -----------------------------------------------------------------
    // 4) Choose the best final state (booster + cheap coupons)
    // -----------------------------------------------------------------
    int best_state   = -1;
    int best_cheap   = 0;          // number of cheap coupons we will finally take
    int best_total   = -1;         // cnt(booster) + cheap

    for (int sid : frontier) {
        int st_cnt = cnts[sid];
        long long st_tok = tokens[sid];

        // how many cheap coupons can we still afford?
        // cheap_prefix is monotone, we need the largest k with cheap_prefix[k] <= st_tok
        int cheap_m = static_cast<int>(
            upper_bound(cheap_prefix.begin(), cheap_prefix.end(), st_tok) - cheap_prefix.begin()
        ) - 1;   // -1 because prefix array has a leading 0

        int total = st_cnt + cheap_m;
        if (total > best_total) {
            best_total = total;
            best_state = sid;
            best_cheap = cheap_m;
        }
    }

    // -----------------------------------------------------------------
    // 5) Reconstruct the answer (order of taken coupons)
    // -----------------------------------------------------------------
    vector<int> answer;
    // booster part (trace back the DP chain)
    for (int sid = best_state; sid != 0; sid = prevs[sid]) {
        answer.push_back(idxs[sid]);          // original index of this booster
    }
    reverse(answer.begin(), answer.end());    // chronological order

    // cheap coupons – they were already sorted by price
    for (int i = 0; i < best_cheap; ++i) {
        answer.push_back(cheap[i].second);    // original index of cheap coupon i
    }

    return answer;
}
#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...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...