Submission #1276463

#TimeUsernameProblemLanguageResultExecution timeMemory
1276463mehrzadFestival (IOI25_festival)C++20
21 / 100
65 ms20272 KiB
#include <bits/stdc++.h>
using namespace std;

struct Coupon {
    int price;      // P[i]
    int type;       // T[i]  (2,3,4)
    int idx;        // original index
    long long C;    // net loss at start, formula (5)
};

std::vector<int> max_coupons(int A, std::vector<int> P, std::vector<int> T) {
    const int N = (int)P.size();

    /* -------------------------------------------------------------
       split coupons into high (T>1) and cheap (T==1), discard
       those with price > A (they can never be bought)
    ------------------------------------------------------------- */
    vector<Coupon> high;
    struct Cheap { int price; int idx; };
    vector<Cheap> cheap;

    for (int i = 0; i < N; ++i) {
        if (P[i] > A) continue;                 // never affordable
        if (T[i] == 1) {
            cheap.push_back({P[i], i});
        } else {
            long long C = 1LL * T[i] * P[i] - 1LL * (T[i] - 1) * A;
            high.push_back({P[i], T[i], i, C});
        }
    }

    /* --------------- cheap coupons : sort by price -------------- */
    sort(cheap.begin(), cheap.end(),
         [](const Cheap& a, const Cheap& b) {
             if (a.price != b.price) return a.price < b.price;
             return a.idx < b.idx;
         });

    vector<long long> cheapPref(cheap.size() + 1, 0);
    for (size_t i = 0; i < cheap.size(); ++i)
        cheapPref[i + 1] = cheapPref[i] + cheap[i].price;

    /* --------------- high coupons : sort by V ------------------- */
    sort(high.begin(), high.end(),
         [&](const Coupon& a, const Coupon& b) {
             long long left  = 1LL * a.price * a.type * (b.type - 1);
             long long right = 1LL * b.price * b.type * (a.type - 1);
             if (left != right) return left < right;                 // smaller V first
             if (a.C != b.C) return a.C < b.C;                       // tie‑break by net loss
             return a.idx < b.idx;
         });

    const int M = (int)high.size();
    const int K = min(M, 60);                     // safe upper bound (≈30)

    /* -------------------------------------------------------------
       DP: dp[i][c] – maximal remaining tokens after considering
                     first i high coupons and buying exactly c of them
       we keep only two rows for the values, but we store the
       whole decision table "taken" for back‑tracking
    ------------------------------------------------------------- */
    const long long NEG = -1;
    vector<long long> dpPrev(K + 1, NEG), dpCurr(K + 1, NEG);
    dpPrev[0] = A;

    // decision table: taken[i][c] == 1  iff coupon i (1‑based) is taken to obtain dp[i][c]
    vector<char> taken((M + 1) * (K + 1), 0);

    for (int i = 1; i <= M; ++i) {
        const Coupon& cp = high[i - 1];
        // copy the “skip” case
        for (int c = 0; c <= K; ++c) dpCurr[c] = dpPrev[c];

        // try to take the i‑th coupon
        for (int c = 1; c <= K; ++c) {
            if (dpPrev[c - 1] != NEG && dpPrev[c - 1] >= cp.price) {
                long long newX = (dpPrev[c - 1] - cp.price) * 1LL * cp.type;
                if (newX > dpCurr[c]) {
                    dpCurr[c] = newX;
                    taken[i * (K + 1) + c] = 1;
                }
            }
        }
        dpPrev.swap(dpCurr);
    }

    /* -------------------------------------------------------------
       choose the best number of high coupons (c) together with cheap ones
    ------------------------------------------------------------- */
    long long bestTotal = 0;
    int bestC = 0;
    long long bestTokens = A;          // tokens after the chosen high coupons

    for (int c = 0; c <= K; ++c) {
        long long tokens = dpPrev[c];
        if (tokens == NEG) continue;
        // maximal number of cheap coupons we can still afford
        int cheapCnt = (int)(upper_bound(cheapPref.begin(),
                                         cheapPref.end(),
                                         tokens) - cheapPref.begin()) - 1;
        long long total = (long long)c + cheapCnt;
        if (total > bestTotal) {
            bestTotal = total;
            bestC = c;
            bestTokens = tokens;
        }
    }

    /* -------------------------------------------------------------
       reconstruct the chosen high coupons
    ------------------------------------------------------------- */
    vector<int> chosenHigh;
    int c = bestC;
    for (int i = M; i >= 1 && c > 0; --i) {
        if (taken[i * (K + 1) + c]) {
            chosenHigh.push_back(high[i - 1].idx);
            --c;
        }
    }
    reverse(chosenHigh.begin(), chosenHigh.end());

    /* -------------------------------------------------------------
       add cheap coupons (the cheapest ones that still fit)
    ------------------------------------------------------------- */
    int cheapCnt = (int)(upper_bound(cheapPref.begin(),
                                     cheapPref.end(),
                                     bestTokens) - cheapPref.begin()) - 1;
    vector<int> answer;
    answer.reserve(chosenHigh.size() + cheapCnt);
    answer.insert(answer.end(), chosenHigh.begin(), chosenHigh.end());
    for (int i = 0; i < cheapCnt; ++i)
        answer.push_back(cheap[i].idx);

    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...