#include using namespace std; static const long long CAP_M = 20000000LL; static const long long CAP_V = 25000000LL; struct Item { string name; int q; long long v; long long m; long long l; }; struct Bundle { int type; int cnt; int mU; int vU; long long val; }; struct State { int mU; int vU; long long val; int prev; int bundle; }; struct FenwickMax { int n; vector bit; FenwickMax(int n_ = 0) { init(n_); } void init(int n_) { n = n_; bit.assign(n + 1, 0); } void update(int i, long long v) { for (; i <= n; i += i & -i) bit[i] = max(bit[i], v); } long long query(int i) const { long long r = 0; for (; i > 0; i -= i & -i) r = max(r, bit[i]); return r; } }; struct Solution { vector cnt; long long value = 0; long long mass = 0; long long vol = 0; }; static inline void skipWS(const string& s, size_t& i) { while (i < s.size() && (unsigned char)s[i] <= 32) i++; } static inline bool consumeChar(const string& s, size_t& i, char c) { skipWS(s, i); if (i < s.size() && s[i] == c) { i++; return true; } return false; } static string parseString(const string& s, size_t& i) { skipWS(s, i); if (i >= s.size() || s[i] != '"') return ""; i++; string out; while (i < s.size()) { char c = s[i++]; if (c == '"') break; if (c == '\\') { if (i >= s.size()) break; char e = s[i++]; if (e == '"' || e == '\\' || e == '/') out.push_back(e); else if (e == 'b') out.push_back('\b'); else if (e == 'f') out.push_back('\f'); else if (e == 'n') out.push_back('\n'); else if (e == 'r') out.push_back('\r'); else if (e == 't') out.push_back('\t'); else if (e == 'u') { // minimal: consume 4 hex digits, ignore unicode properly for (int k = 0; k < 4 && i < s.size(); k++) i++; out.push_back('?'); } } else { out.push_back(c); } } return out; } static long long parseInt(const string& s, size_t& i) { skipWS(s, i); long long x = 0; bool neg = false; if (i < s.size() && s[i] == '-') { neg = true; i++; } while (i < s.size() && isdigit((unsigned char)s[i])) { x = x * 10 + (s[i] - '0'); i++; } return neg ? -x : x; } static bool parseInputJSON(const string& s, vector& items) { size_t i = 0; skipWS(s, i); if (!consumeChar(s, i, '{')) return false; items.clear(); while (true) { skipWS(s, i); if (i >= s.size()) return false; if (s[i] == '}') { i++; break; } string key = parseString(s, i); if (key.empty()) return false; if (!consumeChar(s, i, ':')) return false; if (!consumeChar(s, i, '[')) return false; long long q = parseInt(s, i); if (!consumeChar(s, i, ',')) return false; long long v = parseInt(s, i); if (!consumeChar(s, i, ',')) return false; long long m = parseInt(s, i); if (!consumeChar(s, i, ',')) return false; long long l = parseInt(s, i); if (!consumeChar(s, i, ']')) return false; Item it; it.name = key; it.q = (int)q; it.v = v; it.m = m; it.l = l; items.push_back(it); skipWS(s, i); if (i < s.size() && s[i] == ',') { i++; continue; } if (i < s.size() && s[i] == '}') { i++; break; } } return true; } static inline long long evalSolution(const vector& items, const vector& cnt, long long& mass, long long& vol) { long long val = 0; mass = 0; vol = 0; for (int i = 0; i < (int)items.size(); i++) { long long c = cnt[i]; val += c * items[i].v; mass += c * items[i].m; vol += c * items[i].l; } return val; } static vector pruneFrontier(const vector& pool, vector idx, int capMU, int capVU) { if (idx.empty()) return idx; auto cmp = [&](int a, int b) { const State& A = pool[a]; const State& B = pool[b]; if (A.mU != B.mU) return A.mU < B.mU; if (A.vU != B.vU) return A.vU < B.vU; return A.val > B.val; }; sort(idx.begin(), idx.end(), cmp); // Remove duplicates (mU,vU) keeping highest value vector uniq; uniq.reserve(idx.size()); int lastM = INT_MIN, lastV = INT_MIN; for (int id : idx) { const State& S = pool[id]; if (S.mU < 0 || S.vU < 0 || S.mU > capMU || S.vU > capVU) continue; if (S.mU != lastM || S.vU != lastV) { uniq.push_back(id); lastM = S.mU; lastV = S.vU; } } if (uniq.empty()) return uniq; // Prune within equal mass: increasing vol must have increasing value vector intra; intra.reserve(uniq.size()); size_t p = 0; while (p < uniq.size()) { int m = pool[uniq[p]].mU; long long bestVal = -1; while (p < uniq.size() && pool[uniq[p]].mU == m) { int id = uniq[p++]; long long v = pool[id].val; if (v > bestVal) { intra.push_back(id); bestVal = v; } } } if (intra.empty()) return intra; // Cross-mass dominance pruning using BIT over volume prefix max(value) vector vols; vols.reserve(intra.size()); for (int id : intra) vols.push_back(pool[id].vU); sort(vols.begin(), vols.end()); vols.erase(unique(vols.begin(), vols.end()), vols.end()); FenwickMax bit((int)vols.size()); vector kept; kept.reserve(intra.size()); p = 0; while (p < intra.size()) { int m = pool[intra[p]].mU; size_t start = p; while (p < intra.size() && pool[intra[p]].mU == m) p++; // Query (domination by strictly smaller mass) - OK due to within-mass pruning already done vector groupKept; groupKept.reserve(p - start); for (size_t t = start; t < p; t++) { int id = intra[t]; int volU = pool[id].vU; long long val = pool[id].val; int pos = (int)(lower_bound(vols.begin(), vols.end(), volU) - vols.begin()) + 1; if (bit.query(pos) >= val) continue; groupKept.push_back(id); kept.push_back(id); } // Update after group for (int id : groupKept) { int volU = pool[id].vU; long long val = pool[id].val; int pos = (int)(lower_bound(vols.begin(), vols.end(), volU) - vols.begin()) + 1; bit.update(pos, val); } } // Optional thinning if too large const int HARD_MAX = 150000; const int BUCKET_MAX = 70000; if ((int)kept.size() > HARD_MAX) { int MB = 210, VB = 260; int massStep = max(1, capMU / MB + 1); int volStep = max(1, capVU / VB + 1); vector bestIdx(MB * VB, -1); vector bestVal(MB * VB, -1); for (int id : kept) { const State& S = pool[id]; int mb = min(MB - 1, S.mU / massStep); int vb = min(VB - 1, S.vU / volStep); int pos = mb * VB + vb; if (S.val > bestVal[pos]) { bestVal[pos] = S.val; bestIdx[pos] = id; } } vector thinned; thinned.reserve(MB * VB); for (int id : bestIdx) if (id != -1) thinned.push_back(id); if ((int)thinned.size() > BUCKET_MAX) { sort(thinned.begin(), thinned.end(), [&](int a, int b) { return pool[a].val > pool[b].val; }); thinned.resize(BUCKET_MAX); } return thinned; } return kept; } static vector solveDPScaled(const vector& items, long long massUnit, long long volUnit, int orderMode) { int n = (int)items.size(); int capMU = (int)(CAP_M / massUnit); int capVU = (int)(CAP_V / volUnit); vector bundles; bundles.reserve(200); for (int i = 0; i < n; i++) { int rem = items[i].q; int p = 1; while (rem > 0) { int take = min(p, rem); rem -= take; p <<= 1; long long mTot = (long long)take * items[i].m; long long vTot = (long long)take * items[i].l; int mU = (int)((mTot + massUnit - 1) / massUnit); int vU = (int)((vTot + volUnit - 1) / volUnit); if (mU <= capMU && vU <= capVU) { Bundle b; b.type = i; b.cnt = take; b.mU = mU; b.vU = vU; b.val = (long long)take * items[i].v; bundles.push_back(b); } } } auto densityKey = [&](const Bundle& b) -> long double { long double cost = (long double)b.mU / max(1, capMU) + (long double)b.vU / max(1, capVU); if (cost <= 0) cost = 1e-18L; return (long double)b.val / cost; }; if (orderMode == 1) { sort(bundles.begin(), bundles.end(), [&](const Bundle& a, const Bundle& b) { long double da = densityKey(a), db = densityKey(b); if (da != db) return da > db; return a.val > b.val; }); } else if (orderMode == 2) { sort(bundles.begin(), bundles.end(), [&](const Bundle& a, const Bundle& b) { if (a.val != b.val) return a.val > b.val; if (a.mU != b.mU) return a.mU < b.mU; return a.vU < b.vU; }); } vector pool; pool.reserve(200000); pool.push_back(State{0, 0, 0, -1, -1}); vector frontier; frontier.reserve(1000); frontier.push_back(0); for (int bi = 0; bi < (int)bundles.size(); bi++) { const Bundle& b = bundles[bi]; vector candidates; candidates.reserve(frontier.size() * 2 + 4); for (int id : frontier) candidates.push_back(id); for (int id : frontier) { const State& s = pool[id]; int nm = s.mU + b.mU; int nv = s.vU + b.vU; if (nm > capMU || nv > capVU) continue; State ns; ns.mU = nm; ns.vU = nv; ns.val = s.val + b.val; ns.prev = id; ns.bundle = bi; pool.push_back(ns); candidates.push_back((int)pool.size() - 1); } frontier = pruneFrontier(pool, std::move(candidates), capMU, capVU); if (frontier.empty()) frontier.push_back(0); } // Best final state int bestId = frontier[0]; for (int id : frontier) if (pool[id].val > pool[bestId].val) bestId = id; vector cnt(n, 0); int cur = bestId; while (cur > 0) { int bi = pool[cur].bundle; if (bi >= 0) cnt[bundles[bi].type] += bundles[bi].cnt; cur = pool[cur].prev; if (cur < 0) break; } // Clamp to bounds just in case for (int i = 0; i < n; i++) cnt[i] = min(cnt[i], items[i].q); return cnt; } static void greedyFill(const vector& items, vector& cnt) { int n = (int)items.size(); long long usedM = 0, usedV = 0; for (int i = 0; i < n; i++) { usedM += (long long)cnt[i] * items[i].m; usedV += (long long)cnt[i] * items[i].l; } while (true) { int best = -1; long double bestScore = -1; for (int i = 0; i < n; i++) { if (cnt[i] >= items[i].q) continue; if (usedM + items[i].m > CAP_M) continue; if (usedV + items[i].l > CAP_V) continue; long double cost = (long double)items[i].m / (long double)CAP_M + (long double)items[i].l / (long double)CAP_V; if (cost <= 0) cost = 1e-18L; long double score = (long double)items[i].v / cost; if (score > bestScore) { bestScore = score; best = i; } } if (best < 0) break; long long rem = items[best].q - cnt[best]; long long kM = (CAP_M - usedM) / items[best].m; long long kV = (CAP_V - usedV) / items[best].l; long long add = min(rem, min(kM, kV)); if (add <= 0) break; cnt[best] += (int)add; usedM += add * items[best].m; usedV += add * items[best].l; } } static void localImprove(const vector& items, vector& cnt) { int n = (int)items.size(); long long usedM = 0, usedV = 0; long long usedVal = 0; for (int i = 0; i < n; i++) { usedM += (long long)cnt[i] * items[i].m; usedV += (long long)cnt[i] * items[i].l; usedVal += (long long)cnt[i] * items[i].v; } auto applyGreedy = [&]() { greedyFill(items, cnt); usedM = usedV = usedVal = 0; for (int i = 0; i < n; i++) { usedM += (long long)cnt[i] * items[i].m; usedV += (long long)cnt[i] * items[i].l; usedVal += (long long)cnt[i] * items[i].v; } }; applyGreedy(); auto candidateRemovals = [&](int c) { vector r; int lim = min(c, 20); for (int x = 1; x <= lim; x++) r.push_back(x); for (int x = 1; x < c; x <<= 1) r.push_back(min(c, x)); r.push_back(c); sort(r.begin(), r.end()); r.erase(unique(r.begin(), r.end()), r.end()); return r; }; for (int iter = 0; iter < 120; iter++) { long long bestDelta = 0; int bestI = -1, bestJ = -1, bestR = 0, bestA = 0; for (int i = 0; i < n; i++) { if (cnt[i] <= 0) continue; vector rs = candidateRemovals(cnt[i]); for (int r : rs) { long long newUsedM = usedM - (long long)r * items[i].m; long long newUsedV = usedV - (long long)r * items[i].l; if (newUsedM < 0 || newUsedV < 0) continue; long long availM = CAP_M - newUsedM; long long availV = CAP_V - newUsedV; for (int j = 0; j < n; j++) { long long remJ = items[j].q - cnt[j]; if (j == i) remJ += r; if (remJ <= 0) continue; if (items[j].m > availM || items[j].l > availV) continue; long long maxA = min(remJ, min(availM / items[j].m, availV / items[j].l)); if (maxA <= 0) continue; long long delta = maxA * items[j].v - (long long)r * items[i].v; if (delta > bestDelta) { bestDelta = delta; bestI = i; bestJ = j; bestR = r; bestA = (int)maxA; } } } } if (bestDelta <= 0) break; // Apply best move cnt[bestI] -= bestR; cnt[bestJ] += bestA; // Clamp for (int i = 0; i < n; i++) cnt[i] = max(0, min(cnt[i], items[i].q)); usedM = usedV = usedVal = 0; for (int i = 0; i < n; i++) { usedM += (long long)cnt[i] * items[i].m; usedV += (long long)cnt[i] * items[i].l; usedVal += (long long)cnt[i] * items[i].v; } if (usedM > CAP_M || usedV > CAP_V) { // Repair with greedy from scratch if something went wrong (shouldn't happen) for (int i = 0; i < n; i++) cnt[i] = 0; usedM = usedV = usedVal = 0; } applyGreedy(); } } static vector greedyLambda(const vector& items, long double lambda) { int n = (int)items.size(); vector cnt(n, 0); vector ord(n); iota(ord.begin(), ord.end(), 0); auto dens = [&](int i) -> long double { long double cost = (long double)items[i].m / (long double)CAP_M + lambda * (long double)items[i].l / (long double)CAP_V; if (cost <= 0) cost = 1e-18L; return (long double)items[i].v / cost; }; sort(ord.begin(), ord.end(), [&](int a, int b) { long double da = dens(a), db = dens(b); if (da != db) return da > db; return items[a].v > items[b].v; }); long long usedM = 0, usedV = 0; for (int i : ord) { if (items[i].m > CAP_M || items[i].l > CAP_V) continue; long long k = min(items[i].q, min((CAP_M - usedM) / items[i].m, (CAP_V - usedV) / items[i].l)); if (k <= 0) continue; cnt[i] = (int)k; usedM += k * items[i].m; usedV += k * items[i].l; } greedyFill(items, cnt); return cnt; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); string input((istreambuf_iterator(cin)), istreambuf_iterator()); vector items; if (!parseInputJSON(input, items)) { // Fallback: output empty object cout << "{}\n"; return 0; } int n = (int)items.size(); vector candidates; // DP candidates with multiple scales and orders vector> scales = {{1000,1000}, {2000,2000}, {500,500}, {5000,5000}}; for (auto [mu, vu] : scales) { if (CAP_M % mu != 0 || CAP_V % vu != 0) continue; for (int orderMode = 0; orderMode <= 2; orderMode++) { vector c = solveDPScaled(items, mu, vu, orderMode); Solution sol; sol.cnt = std::move(c); sol.value = evalSolution(items, sol.cnt, sol.mass, sol.vol); if (sol.mass <= CAP_M && sol.vol <= CAP_V) candidates.push_back(sol); } } // Greedy candidates with different lambdas vector lambdas = {0.0L, 0.15L, 0.3L, 0.6L, 1.0L, 1.7L, 3.0L, 6.0L}; for (auto lam : lambdas) { vector c = greedyLambda(items, lam); Solution sol; sol.cnt = std::move(c); sol.value = evalSolution(items, sol.cnt, sol.mass, sol.vol); if (sol.mass <= CAP_M && sol.vol <= CAP_V) candidates.push_back(sol); } // Sort and improve top few sort(candidates.begin(), candidates.end(), [&](const Solution& a, const Solution& b) { return a.value > b.value; }); int improveCount = min((int)candidates.size(), 5); Solution best; best.value = -1; best.cnt.assign(n, 0); for (int idx = 0; idx < (int)candidates.size(); idx++) { Solution sol = candidates[idx]; if (idx < improveCount) { localImprove(items, sol.cnt); sol.value = evalSolution(items, sol.cnt, sol.mass, sol.vol); } if (sol.mass <= CAP_M && sol.vol <= CAP_V && sol.value > best.value) { best = std::move(sol); } } // Final safety clamp and feasibility fix if needed for (int i = 0; i < n; i++) best.cnt[i] = max(0, min(best.cnt[i], items[i].q)); long long mCheck = 0, vCheck = 0; long long valCheck = evalSolution(items, best.cnt, mCheck, vCheck); if (mCheck > CAP_M || vCheck > CAP_V) { // fallback to greedy best.cnt = greedyLambda(items, 1.0L); for (int i = 0; i < n; i++) best.cnt[i] = max(0, min(best.cnt[i], items[i].q)); } // Output JSON with same keys as input (preserve order in items vector) cout << "{"; for (int i = 0; i < n; i++) { if (i) cout << ","; cout << "\n" << " \"" << items[i].name << "\": " << best.cnt[i]; } if (n) cout << "\n"; cout << "}\n"; return 0; }