Submission #1273680

#TimeUsernameProblemLanguageResultExecution timeMemory
1273680lucas110550Festival (IOI25_festival)C++20
100 / 100
308 ms139604 KiB
#include <bits/stdc++.h> using namespace std; struct Coupon { int idx; long long P; int T; }; struct Node { __int128 token; // tokens after processing this state int cnt; // number of multipliers taken int prev; // previous node id int couponIdx; // original index of the coupon taken to reach here (-1 for start) }; static const __int128 INF = (__int128)4'000'000'000'000'000'000LL; // sufficiently large // comparator based on K = P*T/(T-1) bool cmpCoupon(const Coupon& a, const Coupon& b) { if (a.T == 1 && b.T == 1) return a.idx < b.idx; if (a.T == 1) return false; // a after b if (b.T == 1) return true; // a before b // both T > 1 __int128 left = (__int128)a.P * a.T * (b.T - 1); __int128 right = (__int128)b.P * b.T * (a.T - 1); if (left != right) return left < right; return a.idx < b.idx; } // count of cheap coupons (T==1) we can afford with token X int cheapCount(__int128 X, const vector<unsigned long long>& pref, unsigned long long totalCheapSum) { if (X <= 0) return 0; if (X >= ( __int128)totalCheapSum) return (int)pref.size() - 1; unsigned long long x = (unsigned long long)X; // pref[0]=0, pref[i] = sum of first i cheap coupons (i from 0..M) int pos = upper_bound(pref.begin(), pref.end(), x) - pref.begin() - 1; return pos; } std::vector<int> max_coupons(int A, std::vector<int> P, std::vector<int> T) { int N = (int)P.size(); vector<Coupon> all; all.reserve(N); for (int i = 0; i < N; ++i) { all.push_back({i, (long long)P[i], T[i]}); } sort(all.begin(), all.end(), cmpCoupon); // split into multipliers (T>1) and cheap (T==1) vector<Coupon> mult; // T>1 vector<Coupon> cheap; // T==1 for (auto &c : all) { if (c.T == 1) cheap.push_back(c); else mult.push_back(c); } // cheap coupons: sort by price asc for later selection sort(cheap.begin(), cheap.end(), [](const Coupon& a, const Coupon& b){ return a.P < b.P; }); vector<unsigned long long> cheapPref; cheapPref.push_back(0); for (auto &c : cheap) { cheapPref.push_back(cheapPref.back() + (unsigned long long)c.P); } unsigned long long totalCheapSum = cheapPref.back(); // DP over multipliers vector<Node> nodes; nodes.reserve(500000); // start node nodes.push_back({ (__int128)A, 0, -1, -1 }); vector<int> cur; // ids of nondominated states cur.push_back(0); // best answer variables long long bestTotal = cheapCount((__int128)A, cheapPref, totalCheapSum); int bestNodeId = -1; // -1 denotes using no multipliers __int128 bestToken = (__int128)A; for (size_t i = 0; i < mult.size(); ++i) { const Coupon& curC = mult[i]; // map: cnt -> node id with maximal token for that cnt unordered_map<int,int> best; best.reserve(cur.size()*2 + 4); for (int nid : cur) { const Node& nd = nodes[nid]; // skip this coupon auto it = best.find(nd.cnt); if (it == best.end() || nodes[it->second].token < nd.token) best[nd.cnt] = nid; // take this coupon if possible if (nd.token >= (__int128)curC.P) { __int128 newTok = (nd.token - (__int128)curC.P) * (__int128)curC.T; if (newTok > INF) newTok = INF; int newCnt = nd.cnt + 1; Node newNode{newTok, newCnt, nid, curC.idx}; int newId = (int)nodes.size(); nodes.push_back(newNode); auto it2 = best.find(newCnt); if (it2 == best.end() || nodes[it2->second].token < newTok) best[newCnt] = newId; } } // collect and prune dominated states vector<pair<int,int>> vec; vec.reserve(best.size()); for (auto &kv : best) vec.emplace_back(kv.first, kv.second); sort(vec.begin(), vec.end(), [](const pair<int,int>& a, const pair<int,int>& b){ return a.first < b.first; }); cur.clear(); __int128 bestTokenSeen = -1; for (int idx = (int)vec.size() - 1; idx >= 0; --idx) { int nid = vec[idx].second; __int128 tok = nodes[nid].token; if (tok > bestTokenSeen) { cur.push_back(nid); bestTokenSeen = tok; } } // update answer using current states for (int nid : cur) { const Node& nd = nodes[nid]; int cheapCan = cheapCount(nd.token, cheapPref, totalCheapSum); long long total = (long long)nd.cnt + cheapCan; if (total > bestTotal) { bestTotal = total; bestNodeId = nid; bestToken = nd.token; } } } // also consider the case of using no multipliers (already handled) // reconstruct answer vector<int> answer; if (bestNodeId != -1) { // backtrack multiplier indices int curId = bestNodeId; while (curId != -1 && nodes[curId].couponIdx != -1) { answer.push_back(nodes[curId].couponIdx); curId = nodes[curId].prev; } reverse(answer.begin(), answer.end()); // token after taking those multipliers } else { // no multipliers taken bestToken = (__int128)A; } // add cheap coupons (as many as possible) int cheapCan = cheapCount(bestToken, cheapPref, totalCheapSum); for (int i = 0; i < cheapCan; ++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...