Submission #1276461

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

struct ParentInfo {
    int couponIdx;   // original index of the coupon
    int prev;        // index in the parent vector of the previous state
    ParentInfo(int c = -1, int p = -1) : couponIdx(c), prev(p) {}
};

/* --------------------------------------------------------------- */
vector<int> max_coupons(int A, vector<int> P, vector<int> T) {
    const int N = (int)P.size();

    /* -----------------------------------------------------------
       split the coupons
       ----------------------------------------------------------- */
    vector<int> multIdx;          // indices with T > 1
    vector<int> cheapIdx;         // indices with T == 1
    multIdx.reserve(N);
    cheapIdx.reserve(N);
    for (int i = 0; i < N; ++i) {
        if (T[i] == 1) cheapIdx.push_back(i);
        else           multIdx.push_back(i);
    }

    /* -----------------------------------------------------------
       sort multiplier coupons by w = Pi*Ti/(Ti-1)
       (compare Pi*Ti*(Tj-1)  <  Pj*Tj*(Ti-1))
       ----------------------------------------------------------- */
    sort(multIdx.begin(), multIdx.end(),
        [&](int a, int b) {
            long long left  = 1LL * P[a] * T[a] * (T[b] - 1);
            long long right = 1LL * P[b] * T[b] * (T[a] - 1);
            if (left != right) return left < right;
            return a < b;                     // deterministic tie‑break
        });

    /* -----------------------------------------------------------
       DP over a constant number of taken multiplier coupons
       ----------------------------------------------------------- */
    const int MAXK = 60;                     // > log2(1e9)
    const long long INF = (1LL << 60);
    vector<long long> dp(MAXK + 1, INF);     // minimal loss D
    vector<int> bestNode(MAXK + 1, -1);      // index in parent list
    dp[0] = 0;                               // no coupon, loss 0
    int curMax = 0;                          // largest k with dp[k] < INF

    vector<ParentInfo> parent;               // pool of nodes
    parent.reserve(multIdx.size() * 30);

    for (int idx : multIdx) {
        long long price = P[idx];
        int Ti = T[idx];
        long long Bi = 1LL * price * Ti - 1LL * A * (Ti - 1);   // >0

        for (int k = curMax; k >= 0; --k) {
            if (dp[k] == INF) continue;
            if (dp[k] <= (long long)A - price) {               // affordable
                long long newLoss = 1LL * Ti * dp[k] + Bi;     // (4)
                if (newLoss < dp[k + 1]) {
                    dp[k + 1] = newLoss;
                    parent.emplace_back(idx, bestNode[k]);
                    bestNode[k + 1] = (int)parent.size() - 1;
                    if (k + 1 > curMax) curMax = k + 1;
                }
            }
        }
    }

    /* -----------------------------------------------------------
       cheap coupons – sort by price and build prefix sums
       ----------------------------------------------------------- */
    vector<pair<int,int>> cheap;          // (price, original index)
    cheap.reserve(cheapIdx.size());
    for (int idx : cheapIdx) cheap.emplace_back(P[idx], idx);
    sort(cheap.begin(), cheap.end(),
        [&](const pair<int,int>& a, const pair<int,int>& b){
            if (a.first != b.first) return a.first < b.first;
            return a.second < b.second;
        });

    int C = (int)cheap.size();
    vector<long long> pref(C + 1, 0);
    for (int i = 1; i <= C; ++i) pref[i] = pref[i - 1] + cheap[i - 1].first;

    /* -----------------------------------------------------------
       choose the best number of multiplier coupons
       ----------------------------------------------------------- */
    int bestK = 0, bestCheap = 0;
    int bestTotal = -1;
    for (int k = 0; k <= curMax; ++k) {
        if (dp[k] == INF) continue;
        long long tokensLeft = (long long)A - dp[k];
        // maximal cheap coupons that fit into tokensLeft
        int cheapCnt = (int)(upper_bound(pref.begin(), pref.end(), tokensLeft) - pref.begin() - 1);
        int total = k + cheapCnt;
        if (total > bestTotal) {
            bestTotal = total;
            bestK = k;
            bestCheap = cheapCnt;
        }
    }

    /* -----------------------------------------------------------
       reconstruct the answer
       ----------------------------------------------------------- */
    vector<int> answer;

    // multiplier part (in the order we processed them)
    vector<int> multSeq;
    int node = bestNode[bestK];
    while (node != -1) {
        multSeq.push_back(parent[node].couponIdx);
        node = parent[node].prev;
    }
    reverse(multSeq.begin(), multSeq.end());
    answer.insert(answer.end(), multSeq.begin(), multSeq.end());

    // cheap part: first bestCheap cheapest coupons
    for (int i = 0; i < bestCheap; ++i) answer.push_back(cheap[i].second);

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