#include using namespace std; struct Item { string name; long long q, v, m, l; int idx; }; struct Parser { string s; size_t pos = 0; Parser(const string &str): s(str), pos(0) {} void skip_ws() { while (pos < s.size() && isspace((unsigned char)s[pos])) pos++; } bool expect(char c) { skip_ws(); if (pos < s.size() && s[pos] == c) { pos++; return true; } return false; } string read_string() { skip_ws(); if (pos >= s.size() || s[pos] != '"') return ""; pos++; string res; while (pos < s.size()) { char c = s[pos++]; if (c == '"') break; // Assuming no escape sequences needed per problem statement (lowercase ascii keys) res.push_back(c); } return res; } long long read_ll() { skip_ws(); long long sign = 1; if (pos < s.size() && (s[pos] == '+' || s[pos] == '-')) { if (s[pos] == '-') sign = -1; pos++; } long long num = 0; while (pos < s.size() && isdigit((unsigned char)s[pos])) { num = num * 10 + (s[pos] - '0'); pos++; } return num * sign; } vector read_array_numbers() { vector nums; skip_ws(); if (!expect('[')) return nums; while (true) { skip_ws(); // If closing bracket immediately, break if (pos < s.size() && s[pos] == ']') { pos++; break; } long long val = read_ll(); nums.push_back(val); skip_ws(); if (pos < s.size() && s[pos] == ',') { pos++; continue; } else if (pos < s.size() && s[pos] == ']') { pos++; break; } else { // Unexpected, try to continue break; } } return nums; } }; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); // Read entire stdin into a string std::ostringstream oss; oss << cin.rdbuf(); string input = oss.str(); Parser p(input); const long long CAP_M = 20LL * 1000 * 1000; // mg const long long CAP_L = 25LL * 1000 * 1000; // uL vector items; vector order_names; p.skip_ws(); if (!p.expect('{')) { // Fallback: empty output cout << "{\n}\n"; return 0; } while (true) { p.skip_ws(); if (p.pos < input.size() && input[p.pos] == '}') { p.pos++; break; } string key = p.read_string(); if (key.empty()) break; order_names.push_back(key); p.skip_ws(); p.expect(':'); vector arr = p.read_array_numbers(); // expects 4 numbers Item it; it.name = key; if (arr.size() >= 4) { it.q = arr[0]; it.v = arr[1]; it.m = arr[2]; it.l = arr[3]; } else { it.q = it.v = it.m = it.l = 0; } it.idx = (int)items.size(); items.push_back(it); p.skip_ws(); if (p.pos < input.size() && input[p.pos] == ',') { p.pos++; continue; } else if (p.pos < input.size() && input[p.pos] == '}') { p.pos++; break; } else { // continue attempting continue; } } int n = (int)items.size(); if (n == 0) { cout << "{\n"; // no items for (size_t i = 0; i < order_names.size(); ++i) { cout << (i == 0 ? " " : ", ") << "\"" << order_names[i] << "\": 0\n"; } cout << "}\n"; return 0; } // Cap per-item max by capacity feasibility vector maxFeasible(n); for (int i = 0; i < n; ++i) { long long byM = items[i].m > 0 ? (CAP_M / items[i].m) : 0; long long byL = items[i].l > 0 ? (CAP_L / items[i].l) : 0; long long mf = min(items[i].q, min(byM, byL)); if (mf < 0) mf = 0; maxFeasible[i] = mf; } auto greedy_fill_with_order = [&](const vector& ord, const vector& baseCounts, long long usedM, long long usedL) { vector x = baseCounts; long long remM = CAP_M - usedM; long long remL = CAP_L - usedL; long long val = 0; for (int i = 0; i < n; ++i) { if (x[i] < 0) x[i] = 0; if (x[i] > maxFeasible[i]) x[i] = maxFeasible[i]; val += x[i] * items[i].v; } for (int idx : ord) { if (items[idx].m == 0 || items[idx].l == 0) continue; // per statement, shouldn't happen long long canq = maxFeasible[idx] - x[idx]; if (canq <= 0) continue; long long cm = remM / items[idx].m; long long cl = remL / items[idx].l; long long can = min(canq, min(cm, cl)); if (can <= 0) continue; x[idx] += can; remM -= can * items[idx].m; remL -= can * items[idx].l; val += can * items[idx].v; if (remM <= 0 || remL <= 0) break; } return pair, long long>(x, val); }; auto greedy_fill = [&](const vector& ord) { vector base(n, 0); return greedy_fill_with_order(ord, base, 0, 0); }; auto build_order_by_w = [&](double w) { vector> dens; dens.reserve(n); for (int i = 0; i < n; ++i) { // Normalize by capacities to make scales comparable double denom = w * (double)items[i].m / (double)CAP_M + (1.0 - w) * (double)items[i].l / (double)CAP_L; if (denom <= 0) denom = 1e-18; double score = (double)items[i].v / denom; dens.emplace_back(score, i); } sort(dens.begin(), dens.end(), [&](const auto& a, const auto& b){ if (a.first != b.first) return a.first > b.first; // tie-breakers: higher value then lower size if (items[a.second].v != items[b.second].v) return items[a.second].v > items[b.second].v; long long sa = items[a.second].m + items[a.second].l; long long sb = items[b.second].m + items[b.second].l; if (sa != sb) return sa < sb; return a.second < b.second; }); vector ord; ord.reserve(n); for (auto &pr : dens) ord.push_back(pr.second); return ord; }; auto build_order_by_custom_desc = [&](const vector& score) { vector ord(n); iota(ord.begin(), ord.end(), 0); sort(ord.begin(), ord.end(), [&](int a, int b){ if (score[a] != score[b]) return score[a] > score[b]; if (items[a].v != items[b].v) return items[a].v > items[b].v; long long sa = items[a].m + items[a].l; long long sb = items[b].m + items[b].l; if (sa != sb) return sa < sb; return a < b; }); return ord; }; auto build_order_small_size_first = [&]() { vector> arr; arr.reserve(n); for (int i = 0; i < n; ++i) { double s = (double)items[i].m / (double)CAP_M + (double)items[i].l / (double)CAP_L; arr.emplace_back(s, i); } sort(arr.begin(), arr.end(), [&](const auto& a, const auto& b){ if (a.first != b.first) return a.first < b.first; if (items[a.second].v != items[b.second].v) return items[a.second].v > items[b.second].v; return a.second < b.second; }); vector ord; for (auto &pr : arr) ord.push_back(pr.second); return ord; }; vector> orders; auto add_order_if_new = [&](const vector& ord) { for (auto &o : orders) { if (o == ord) return; } orders.push_back(ord); }; // Various heuristic orders vector ws = {0.0, 0.2, 0.4, 0.5, 0.6, 0.8, 1.0}; for (double w : ws) add_order_if_new(build_order_by_w(w)); // value per max(m/M, l/L) { vector sc(n); for (int i = 0; i < n; ++i) { double denom = max((double)items[i].m / (double)CAP_M, (double)items[i].l / (double)CAP_L); if (denom <= 0) denom = 1e-18; sc[i] = (double)items[i].v / denom; } add_order_if_new(build_order_by_custom_desc(sc)); } // value per mass (same as w=1 but include anyway due to tiebreak) { vector sc(n); for (int i = 0; i < n; ++i) { double denom = (double)items[i].m / (double)CAP_M; if (denom <= 0) denom = 1e-18; sc[i] = (double)items[i].v / denom; } add_order_if_new(build_order_by_custom_desc(sc)); } // value per volume (w=0) { vector sc(n); for (int i = 0; i < n; ++i) { double denom = (double)items[i].l / (double)CAP_L; if (denom <= 0) denom = 1e-18; sc[i] = (double)items[i].v / denom; } add_order_if_new(build_order_by_custom_desc(sc)); } // pure value { vector sc(n); for (int i = 0; i < n; ++i) sc[i] = (double)items[i].v; add_order_if_new(build_order_by_custom_desc(sc)); } // small size first add_order_if_new(build_order_small_size_first()); // Initial solutions via greedy on multiple orders vector bestX(n, 0); long long bestV = 0; long long bestUsedM = 0, bestUsedL = 0; vector bestOrd; for (auto &ord : orders) { auto res = greedy_fill(ord); auto &x = res.first; long long v = res.second; if (v > bestV) { bestV = v; bestX = x; long long usedM = 0, usedL = 0; for (int i = 0; i < n; ++i) { usedM += x[i] * items[i].m; usedL += x[i] * items[i].l; } bestUsedM = usedM; bestUsedL = usedL; bestOrd = ord; } } // Local improvement: hill climbing via remove-then-refill auto start = chrono::steady_clock::now(); auto elapsed_ms = [&]() { return chrono::duration_cast(chrono::steady_clock::now() - start).count(); }; auto build_dynamic_order = [&](long long usedM, long long usedL) { double um = (double)usedM / (double)CAP_M; double ul = (double)usedL / (double)CAP_L; double denom = um + ul; double w = 0.5; if (denom > 1e-12) { w = um / denom; } return build_order_by_w(w); }; const long long time_limit_ms = 900; // keep some margin bool improved = true; while (improved && elapsed_ms() < time_limit_ms) { improved = false; for (int i = 0; i < n && elapsed_ms() < time_limit_ms; ++i) { if (bestX[i] <= 0) continue; long long max_remove = min(4, bestX[i]); for (long long r = 1; r <= max_remove && elapsed_ms() < time_limit_ms; ++r) { vector curX = bestX; curX[i] -= r; long long curUsedM = bestUsedM - r * items[i].m; long long curUsedL = bestUsedL - r * items[i].l; long long curV = bestV - r * items[i].v; if (curUsedM < 0) curUsedM = 0; // safety if (curUsedL < 0) curUsedL = 0; vector dynOrd = build_dynamic_order(curUsedM, curUsedL); // Try dynamic order, then fallback to bestOrd bool found = false; for (int attempt = 0; attempt < 2; ++attempt) { const vector& ord = (attempt == 0 ? dynOrd : bestOrd.size() ? bestOrd : dynOrd); auto res = greedy_fill_with_order(ord, curX, curUsedM, curUsedL); auto &x2 = res.first; long long v2 = res.second; if (v2 > bestV) { // accept bestX = x2; bestV = v2; long long uM = 0, uL = 0; for (int k = 0; k < n; ++k) { uM += bestX[k] * items[k].m; uL += bestX[k] * items[k].l; } bestUsedM = uM; bestUsedL = uL; improved = true; found = true; break; } } if (found) break; } if (improved) break; } } // Ensure counts do not exceed q and fit capacities (safety trim if any numerical issues) for (int i = 0; i < n; ++i) { if (bestX[i] < 0) bestX[i] = 0; if (bestX[i] > items[i].q) bestX[i] = items[i].q; } // Hard trim in case of slight over-capacity (shouldn't happen) auto totalM = [&]() { long long s = 0; for (int i = 0; i < n; ++i) s += bestX[i] * items[i].m; return s; }; auto totalL = [&]() { long long s = 0; for (int i = 0; i < n; ++i) s += bestX[i] * items[i].l; return s; }; long long curM = totalM(); long long curL = totalL(); if (curM > CAP_M || curL > CAP_L) { // Remove from least efficient items until fits vector ord = build_order_by_w(0.5); // reverse (least efficient last in ord) -> remove from end to start for (int idx = n - 1; idx >= 0 && (curM > CAP_M || curL > CAP_L); --idx) { int i = ord[idx]; while (bestX[i] > 0 && (curM > CAP_M || curL > CAP_L)) { bestX[i]--; curM -= items[i].m; curL -= items[i].l; } } } // Output JSON with same keys as input (in original order) // Map names to counts (by index), ensure using input order_names unordered_map name_to_count; name_to_count.reserve(n * 2); for (int i = 0; i < n; ++i) { name_to_count[items[i].name] = bestX[i]; } cout << "{\n"; for (size_t i = 0; i < order_names.size(); ++i) { const string &nm = order_names[i]; long long cnt = 0; auto it = name_to_count.find(nm); if (it != name_to_count.end()) cnt = it->second; cout << (i == 0 ? " " : ", ") << "\"" << nm << "\": " << cnt << "\n"; } cout << "}\n"; return 0; }