제출 #1368126

#제출 시각아이디문제언어결과실행 시간메모리
1368126llm축제 (IOI25_festival)C++20
100 / 100
64 ms27032 KiB
#include <vector>
#include <algorithm>

using namespace std;

struct Coupon {
    long long P, T;
    int id;
};

// Sort T > 1 coupons by P_i * T_i / (T_i - 1) ascending
bool comp_Tgt1(const Coupon& a, const Coupon& b) {
    long long lhs = a.P * a.T * (b.T - 1);
    long long rhs = b.P * b.T * (a.T - 1);
    if (lhs != rhs) return lhs < rhs;
    return a.id < b.id;
}

// Sort T == 1 coupons by P_i ascending
bool comp_Teq1(const Coupon& a, const Coupon& b) {
    if (a.P != b.P) return a.P < b.P;
    return a.id < b.id;
}

std::vector<int> max_coupons(int A, std::vector<int> P, std::vector<int> T) {
    int n = P.size();
    vector<Coupon> t_gt_1;
    vector<Coupon> t_eq_1;

    for (int i = 0; i < n; ++i) {
        if (T[i] > 1) {
            t_gt_1.push_back({(long long)P[i], (long long)T[i], i});
        } else {
            t_eq_1.push_back({(long long)P[i], (long long)T[i], i});
        }
    }

    sort(t_gt_1.begin(), t_gt_1.end(), comp_Tgt1);
    sort(t_eq_1.begin(), t_eq_1.end(), comp_Teq1);

    long long X = A;
    vector<int> ans;
    // Cap X to prevent overflow but ensure we stay wealthy enough to afford any coupon
    long long INF = 2000000000000000LL; 

    vector<Coupon> loss_list;
    bool loss_started = false;

    // Process Gain/Neutral T > 1 coupons
    for (const auto& c : t_gt_1) {
        if (!loss_started) {
            long long lhs = X * (c.T - 1);
            long long rhs = c.P * c.T;
            
            if (lhs >= rhs) { // Gain or Neutral phase
                X = (X - c.P) * c.T;
                X = min(X, INF);
                ans.push_back(c.id);
            } else {
                loss_started = true;
                loss_list.push_back(c);
            }
        } else {
            loss_list.push_back(c);
        }
    }

    int M = loss_list.size();
    int K_MAX = 65; // Safe upper bound for consecutive valid Loss purchases

    // 1D DP table for 0/1 Knapsack optimization
    vector<long long> dp(K_MAX + 1, -1);
    vector<vector<bool>> parent(M + 1, vector<bool>(K_MAX + 1, false));

    dp[0] = X;

    for (int i = 1; i <= M; ++i) {
        long long p_val = loss_list[i-1].P;
        long long t_val = loss_list[i-1].T;

        // Iterate backwards for optimized 1D state transition
        for (int k = K_MAX; k >= 1; --k) {
            if (dp[k-1] != -1 && dp[k-1] >= p_val) {
                long long val = (dp[k-1] - p_val) * t_val;
                val = min(val, INF);
                
                if (val > dp[k]) {
                    dp[k] = val;
                    parent[i][k] = true;
                }
            }
        }
    }

    vector<long long> pref(t_eq_1.size() + 1, 0);
    for (size_t i = 0; i < t_eq_1.size(); ++i) {
        pref[i+1] = pref[i] + t_eq_1[i].P;
    }

    int best_k = -1;
    int max_total = -1;
    int best_c = -1;

    // Check optimal combination of Loss coupons + T=1 additive coupons
    for (int k = 0; k <= K_MAX; ++k) {
        if (dp[k] != -1) {
            long long rem = dp[k];
            int c = upper_bound(pref.begin(), pref.end(), rem) - pref.begin() - 1;
            
            if (k + c > max_total) {
                max_total = k + c;
                best_k = k;
                best_c = c;
            }
        }
    }

    // Reconstruct the picked path among "Loss" multiplier coupons
    if (best_k > 0) {
        int curr_k = best_k;
        vector<int> loss_picks;
        for (int i = M; i >= 1; --i) {
            if (curr_k > 0 && parent[i][curr_k]) {
                loss_picks.push_back(loss_list[i-1].id);
                curr_k--;
            }
        }
        reverse(loss_picks.begin(), loss_picks.end());
        for (int id : loss_picks) {
            ans.push_back(id);
        }
    }

    // Spend the remaining tokens strictly on optimal T = 1 coupons
    for (int i = 0; i < best_c; ++i) {
        ans.push_back(t_eq_1[i].id);
    }

    return ans;
}
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…