Submission #1254707

#TimeUsernameProblemLanguageResultExecution timeMemory
1254707fasterthanyouFestival (IOI25_festival)C++20
12 / 100
1096 ms18092 KiB
#include <bits/stdc++.h> using namespace std; using ll = long long; struct Item { ll P; int T; int id; }; // min-heap by price within a fixed T (since K is monotone in P when T fixed) template<class Tpair> using MinHeap = priority_queue<Tpair, vector<Tpair>, greater<Tpair>>; static inline bool lessK(ll P1, int T1, ll P2, int T2) { // compare P1*T1/(T1-1) < P2*T2/(T2-1) without floating // i.e. P1*T1*(T2-1) < P2*T2*(T1-1) // T in {2,3,4}, (T-1)>0 __int128 lhs = (__int128)P1 * T1 * (T2 - 1); __int128 rhs = (__int128)P2 * T2 * (T1 - 1); if (lhs != rhs) return lhs < rhs; // tie-break: prefer larger multiplier to boost future capacity return T1 > T2; } vector<int> max_coupons(int A, vector<int> P, vector<int> T) { const ll INF = (ll)4e18; // cap to prevent overflow int N = (int)P.size(); // Split into T==1 and T>1 buckets, each store (P, id) vector<pair<ll,int>> ones; array<vector<pair<ll,int>>, 5> bucket; // bucket[2], bucket[3], bucket[4] for (int i = 0; i < N; ++i) { if (T[i] == 1) ones.emplace_back((ll)P[i], i); else bucket[T[i]].emplace_back((ll)P[i], i); } // Sort each by price ascending (we'll push into heaps when price <= X) sort(ones.begin(), ones.end()); for (int t : {2,3,4}) sort(bucket[t].begin(), bucket[t].end()); // Pointers per bucket to stream-in affordable items array<int, 5> ptr{}; // default 0 // Available heaps: per T, heap of (P, id) MinHeap<pair<ll,int>> avail2, avail3, avail4; auto push_affordable = [&](ll X) { // move items with P <= X into avail heaps for (int t : {2,3,4}) { auto &vec = bucket[t]; int &j = ptr[t]; while (j < (int)vec.size() && vec[j].first <= X) { if (t == 2) avail2.push(vec[j]); else if (t == 3) avail3.push(vec[j]); else avail4.push(vec[j]); ++j; } } }; ll X = A; push_affordable(X); // Record the dynamic path of T>1 choices so we can later choose best prefix struct Step { int id; ll P; int T; ll afterX; }; vector<Step> path; // Greedy loop among T>1: at each step pick the affordable item with minimal K across {2,3,4} heap tops while (true) { // pick candidate tops (must check affordable at *current* X) bool has2 = !avail2.empty() && avail2.top().first <= X; bool has3 = !avail3.empty() && avail3.top().first <= X; bool has4 = !avail4.empty() && avail4.top().first <= X; if (!has2 && !has3 && !has4) break; // choose by minimal K; ties prefer larger T ll cP = -1; int cT = -1; int cid = -1; auto consider = [&](ll p, int t, int id){ if (cT == -1 || lessK(p,t,cP,cT)) { cP=p; cT=t; cid=id; } }; if (has2) consider(avail2.top().first, 2, avail2.top().second); if (has3) consider(avail3.top().first, 3, avail3.top().second); if (has4) consider(avail4.top().first, 4, avail4.top().second); // pop chosen from its heap if (cT == 2) avail2.pop(); else if (cT == 3) avail3.pop(); else avail4.pop(); // buy it if (X < cP) break; // shouldn't happen due to has* checks ll NX = X - cP; // multiply with cap if (NX > 0 && cT > 1) { __int128 tmp = (__int128)NX * cT; NX = (tmp > INF ? INF : (ll)tmp); } else { NX = NX * cT; // could be 0 } X = NX; path.push_back({cid, cP, cT, X}); // newly affordable items may appear push_affordable(X); } // Pre-compute, for each prefix length r, total count = r + (#ones affordable from X_r) // First consider r=0 (no T>1) auto count_ones_from = [&](ll x)->int{ int cnt = 0; for (auto &pr : ones) { if (x >= pr.first) { x -= pr.first; ++cnt; } else break; } return cnt; }; int best_r = 0; ll curX = A; int best_total = count_ones_from(curX); for (int r = 1; r <= (int)path.size(); ++r) { ll xr = path[r-1].afterX; int total = r + count_ones_from(xr); if (total > best_total) { best_total = total; best_r = r; } } // Reconstruct answer order: take first best_r steps from path, then eat ones greedily vector<int> ans; ans.reserve(best_total); ll x2 = A; for (int i = 0; i < best_r; ++i) { auto [id, p, t, afterX] = path[i]; ans.push_back(id); // forward-simulate X to align ll NX = x2 - p; if (NX > 0 && t > 1) { __int128 tmp = (__int128)NX * t; NX = (tmp > INF ? INF : (ll)tmp); } else { NX = NX * t; } x2 = NX; } for (auto &pr : ones) { if (x2 >= pr.first) { x2 -= pr.first; ans.push_back(pr.second); } else break; } return ans; }
#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...