제출 #1325591

#제출 시각아이디문제언어결과실행 시간메모리
1325591kregs축제 (IOI25_festival)C++20
36 / 100
70 ms12836 KiB
#include <vector>
#include <algorithm>
#include <iostream>
#include <queue>
#include <tuple>
#include <cstdint>

using namespace std;

// Use explicit long long to prevent overflow
typedef long long ll;

// State structure for BFS queue
// using int instead of uint8_t to prevent header/type issues
struct State {
    int u1; // Count of Type 2 coupons bought in BFS phase
    int u2; // Count of Type 3 coupons bought in BFS phase
    int u3; // Count of Type 4 coupons bought in BFS phase
};

// DP Array to replace Map
// Dimensions: [65][65][65]. 
// Stores the max money achievable for a specific count of T2, T3, T4 coupons.
ll dp[65][65][65]; 

struct Candidate {
    int t_idx; // 1 for T2, 2 for T3, 3 for T4
    int v_idx; // index in the respective sorted vector
    ll price;
};

std::vector<int> max_coupons(int A, std::vector<int> P, std::vector<int> T) {
    int n = P.size();
    
    // 1. Separate coupons into sorted buckets
    // v[0]=Spenders, v[1]=Type2, v[2]=Type3, v[3]=Type4
    vector<vector<pair<ll, int>>> v(4);
    ll sum_all_prices = 0;
    
    for(int i=0; i<n; ++i) {
        if(T[i] >= 1 && T[i] <= 4) {
            v[T[i]-1].push_back({(ll)P[i], i});
            sum_all_prices += (ll)P[i];
        }
    }
    
    // Sort buckets by Price (Cheapest first)
    for(int i=0; i<4; ++i) sort(v[i].begin(), v[i].end());
    
    // Define "Infinite Money" Cap
    ll MAX_VAL = 2000000000000000LL; // 2e15 baseline
    if (sum_all_prices + 2000 > MAX_VAL) MAX_VAL = sum_all_prices + 2000;
    // Cap to avoid LL overflow during multiplications
    if (MAX_VAL > 4000000000000000000LL) MAX_VAL = 4000000000000000000LL; 

    // 2. Profit Phase Candidates (Heuristic)
    vector<Candidate> candidates;
    for(int t=1; t<4; ++t) {
        for(size_t i=0; i<v[t].size(); ++i) {
            candidates.push_back({t, (int)i, v[t][i].first});
        }
    }
    
    // Sort by efficiency P*T / (T-1) using cross-multiplication
    sort(candidates.begin(), candidates.end(), [](const Candidate& a, const Candidate& b){
        ll Ta = a.t_idx + 1;
        ll Tb = b.t_idx + 1;
        unsigned __int128 v1 = (unsigned __int128)a.price * Ta * (Tb - 1);
        unsigned __int128 v2 = (unsigned __int128)b.price * Tb * (Ta - 1);
        return v1 < v2;
    });
    
    // 3. Execute Profit Phase
    // Greedily buy anything that strictly increases our money.
    vector<int> res_indices;
    int c[4] = {0, 0, 0, 0}; // c[1]=count of T2 used, etc.
    ll cur = A;
    
    for(const auto& cand : candidates) {
        int t = cand.t_idx; 
        if(cand.v_idx == c[t]) {
            ll p = v[t][c[t]].first;
            if(cur < p) continue; 
            
            ll mult = t + 1;
            ll nxt = (cur - p) * mult;
            if(nxt > MAX_VAL) nxt = MAX_VAL;
            
            if(nxt > cur) {
                cur = nxt;
                res_indices.push_back(v[t][c[t]].second);
                c[t]++;
            }
        }
    }
    
    // 4. BFS Phase Setup
    int base[4]; // Offset from profit phase
    base[1] = c[1]; base[2] = c[2]; base[3] = c[3];
    
    // Reset DP Array to -1
    for(int i=0; i<65; ++i)
        for(int j=0; j<65; ++j)
            for(int k=0; k<65; ++k)
                dp[i][j][k] = -1;
                
    dp[0][0][0] = cur;
    
    queue<State> q;
    q.push({0,0,0});
    
    int max_total = 0;
    State best_state = {0,0,0};
    
    // Precompute Spender (T1) prefix sums for fast lookup
    vector<ll> p1;
    p1.push_back(0);
    for(auto& x : v[0]) p1.push_back(p1.back() + x.first);
    
    // Helper to update global best
    auto update = [&](ll money, int u1, int u2, int u3) {
        auto it = upper_bound(p1.begin(), p1.end(), money);
        int c1 = (int)(it - p1.begin()) - 1;
        int tot = (int)res_indices.size() + u1 + u2 + u3 + c1;
        if(tot > max_total) {
            max_total = tot;
            best_state = {u1, u2, u3};
        }
    };
    
    update(cur, 0, 0, 0);
    
    // 5. BFS Execution
    while(!q.empty()) {
        State s = q.front();
        q.pop();
        
        int u1 = s.u1, u2 = s.u2, u3 = s.u3;
        ll m = dp[u1][u2][u3];
        
        // PRUNING: If money is saturated, we can buy EVERYTHING remaining.
        if(m >= MAX_VAL) {
            // Calculate remaining items for T2, T3, T4
            int rem2 = max(0, (int)v[1].size() - (base[1] + u1));
            int rem3 = max(0, (int)v[2].size() - (base[2] + u2));
            int rem4 = max(0, (int)v[3].size() - (base[3] + u3));
            int rem1 = (int)v[0].size(); // All spenders
            
            int tot = (int)res_indices.size() + u1 + u2 + u3 + rem1 + rem2 + rem3 + rem4;
            if(tot > max_total) {
                max_total = tot;
                best_state = s; 
            }
            continue; // Stop expanding this saturated branch
        }
        
        // Try adding next Type 2
        if(base[1] + u1 < (int)v[1].size() && u1 + 1 < 65) {
            ll p = v[1][base[1] + u1].first;
            if(m >= p) {
                ll nm = (m - p) * 2;
                if(nm > MAX_VAL) nm = MAX_VAL;
                
                if(nm > dp[u1+1][u2][u3]) {
                    dp[u1+1][u2][u3] = nm;
                    q.push({u1+1, u2, u3});
                    update(nm, u1+1, u2, u3);
                }
            }
        }
        
        // Try adding next Type 3
        if(base[2] + u2 < (int)v[2].size() && u2 + 1 < 65) {
            ll p = v[2][base[2] + u2].first;
            if(m >= p) {
                ll nm = (m - p) * 3;
                if(nm > MAX_VAL) nm = MAX_VAL;
                
                if(nm > dp[u1][u2+1][u3]) {
                    dp[u1][u2+1][u3] = nm;
                    q.push({u1, u2+1, u3});
                    update(nm, u1, u2+1, u3);
                }
            }
        }
        
        // Try adding next Type 4
        if(base[3] + u3 < (int)v[3].size() && u3 + 1 < 65) {
            ll p = v[3][base[3] + u3].first;
            if(m >= p) {
                ll nm = (m - p) * 4;
                if(nm > MAX_VAL) nm = MAX_VAL;
                
                if(nm > dp[u1][u2][u3+1]) {
                    dp[u1][u2][u3+1] = nm;
                    q.push({u1, u2, u3+1});
                    update(nm, u1, u2, u3+1);
                }
            }
        }
    }
    
    // 6. Reconstruction
    // Backtrack from best_state to find the BFS coupons
    vector<int> bfs_res;
    int cu1 = best_state.u1;
    int cu2 = best_state.u2;
    int cu3 = best_state.u3;
    
    while(cu1 > 0 || cu2 > 0 || cu3 > 0) {
        ll curr_m = dp[cu1][cu2][cu3];
        bool found = false;
        
        // Try T2 parent
        if(cu1 > 0) {
            ll prev = dp[cu1-1][cu2][cu3];
            if(prev != -1) {
                ll p = v[1][base[1] + cu1 - 1].first;
                ll check = (prev - p) * 2;
                if(check > MAX_VAL) check = MAX_VAL;
                if(check == curr_m) {
                    bfs_res.push_back(v[1][base[1] + cu1 - 1].second);
                    cu1--; found = true;
                }
            }
        }
        // Try T3 parent
        if(!found && cu2 > 0) {
            ll prev = dp[cu1][cu2-1][cu3];
            if(prev != -1) {
                ll p = v[2][base[2] + cu2 - 1].first;
                ll check = (prev - p) * 3;
                if(check > MAX_VAL) check = MAX_VAL;
                if(check == curr_m) {
                    bfs_res.push_back(v[2][base[2] + cu2 - 1].second);
                    cu2--; found = true;
                }
            }
        }
        // Try T4 parent
        if(!found && cu3 > 0) {
            ll prev = dp[cu1][cu2][cu3-1];
            if(prev != -1) {
                ll p = v[3][base[3] + cu3 - 1].first;
                ll check = (prev - p) * 4;
                if(check > MAX_VAL) check = MAX_VAL;
                if(check == curr_m) {
                    bfs_res.push_back(v[3][base[3] + cu3 - 1].second);
                    cu3--; found = true;
                }
            }
        }
        if(!found) break; 
    }
    
    reverse(bfs_res.begin(), bfs_res.end());
    res_indices.insert(res_indices.end(), bfs_res.begin(), bfs_res.end());
    
    // 7. Add Remaining Items
    ll fin_m = dp[best_state.u1][best_state.u2][best_state.u3];
    
    // Add Spenders (Type 1)
    auto it = upper_bound(p1.begin(), p1.end(), fin_m);
    int c1 = (int)(it - p1.begin()) - 1;
    for(int i=0; i<c1; ++i) res_indices.push_back(v[0][i].second);
    
    // If we hit Infinite Money, add all remaining Multipliers too
    if(fin_m >= MAX_VAL) {
        // T2
        for(size_t i = base[1] + best_state.u1; i < v[1].size(); ++i) 
            res_indices.push_back(v[1][i].second);
        // T3
        for(size_t i = base[2] + best_state.u2; i < v[2].size(); ++i) 
            res_indices.push_back(v[2][i].second);
        // T4
        for(size_t i = base[3] + best_state.u3; i < v[3].size(); ++i) 
            res_indices.push_back(v[3][i].second);
    }

    return res_indices;
}
#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...