| #include <bits/stdc++.h> |
| using namespace std; |
|
|
| struct Item { |
| string name; |
| long long q, v, m, l; |
| double nm, nl; |
| }; |
|
|
| struct Parser { |
| string s; |
| size_t i = 0; |
|
|
| Parser(const string& str): s(str), i(0) {} |
|
|
| void skipWS() { |
| while (i < s.size() && isspace((unsigned char)s[i])) i++; |
| } |
|
|
| bool consume(char c) { |
| skipWS(); |
| if (i < s.size() && s[i] == c) { i++; return true; } |
| return false; |
| } |
|
|
| void expect(char c) { |
| skipWS(); |
| if (i >= s.size() || s[i] != c) { |
| |
| throw runtime_error("JSON parse error: expected char"); |
| } |
| i++; |
| } |
|
|
| string parseString() { |
| skipWS(); |
| if (i >= s.size() || s[i] != '"') throw runtime_error("JSON parse error: expected string"); |
| i++; |
| string res; |
| while (i < s.size()) { |
| char c = s[i++]; |
| if (c == '"') break; |
| |
| res.push_back(c); |
| } |
| return res; |
| } |
|
|
| long long parseNumber() { |
| skipWS(); |
| bool neg = false; |
| if (i < s.size() && s[i] == '-') { neg = true; i++; } |
| long long val = 0; |
| bool any = false; |
| while (i < s.size() && isdigit((unsigned char)s[i])) { |
| any = true; |
| val = val * 10 + (s[i] - '0'); |
| i++; |
| } |
| if (!any) throw runtime_error("JSON parse error: expected number"); |
| return neg ? -val : val; |
| } |
|
|
| vector<long long> parseArrayOfNumbers() { |
| skipWS(); |
| expect('['); |
| vector<long long> nums; |
| while (true) { |
| skipWS(); |
| if (consume(']')) break; |
| long long num = parseNumber(); |
| nums.push_back(num); |
| skipWS(); |
| if (consume(']')) break; |
| consume(','); |
| } |
| return nums; |
| } |
|
|
| vector<Item> parseItems() { |
| skipWS(); |
| expect('{'); |
| vector<Item> items; |
| while (true) { |
| skipWS(); |
| if (consume('}')) break; |
| string key = parseString(); |
| skipWS(); |
| expect(':'); |
| vector<long long> arr = parseArrayOfNumbers(); |
| |
| long long q = 0, v = 0, m = 0, l = 0; |
| if (arr.size() >= 4) { |
| q = arr[0]; v = arr[1]; m = arr[2]; l = arr[3]; |
| } else { |
| throw runtime_error("JSON parse error: array size < 4"); |
| } |
| Item it; it.name = key; it.q = q; it.v = v; it.m = m; it.l = l; |
| items.push_back(it); |
| skipWS(); |
| if (consume('}')) break; |
| consume(','); |
| } |
| return items; |
| } |
| }; |
|
|
| static const long long M_CAP = 20000000LL; |
| static const long long L_CAP = 25000000LL; |
|
|
| struct Solution { |
| vector<long long> x; |
| long long val = 0; |
| long long remM = M_CAP; |
| long long remL = L_CAP; |
| }; |
|
|
| long long computeValue(const vector<Item>& items, const vector<long long>& x) { |
| long long val = 0; |
| for (size_t i = 0; i < items.size(); ++i) { |
| val += x[i] * items[i].v; |
| } |
| return val; |
| } |
|
|
| Solution greedy_with_order(const vector<Item>& items, const vector<int>& order) { |
| Solution sol; |
| int n = (int)items.size(); |
| sol.x.assign(n, 0); |
| sol.remM = M_CAP; |
| sol.remL = L_CAP; |
| for (int idx : order) { |
| const Item& it = items[idx]; |
| if (it.m > sol.remM || it.l > sol.remL) { |
| long long canM = (it.m == 0) ? it.q : (sol.remM / it.m); |
| long long canL = (it.l == 0) ? it.q : (sol.remL / it.l); |
| long long can = min({it.q, canM, canL}); |
| |
| if (can <= 0) continue; |
| sol.x[idx] += can; |
| sol.remM -= can * it.m; |
| sol.remL -= can * it.l; |
| } else { |
| long long canM = (it.m == 0) ? it.q : (sol.remM / it.m); |
| long long canL = (it.l == 0) ? it.q : (sol.remL / it.l); |
| long long can = min({it.q, canM, canL}); |
| if (can <= 0) continue; |
| sol.x[idx] += can; |
| sol.remM -= can * it.m; |
| sol.remL -= can * it.l; |
| } |
| } |
| sol.val = computeValue(items, sol.x); |
| return sol; |
| } |
|
|
| vector<int> order_by_metric(const vector<Item>& items, function<double(const Item&)> metric) { |
| int n = (int)items.size(); |
| vector<int> order(n); |
| iota(order.begin(), order.end(), 0); |
| vector<double> score(n); |
| for (int i = 0; i < n; ++i) score[i] = metric(items[i]); |
| stable_sort(order.begin(), order.end(), [&](int a, int b){ |
| if (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 score[a] > score[b]; |
| }); |
| return order; |
| } |
|
|
| void init_norms(vector<Item>& items) { |
| for (auto &it : items) { |
| it.nm = (double)it.m / (double)M_CAP; |
| it.nl = (double)it.l / (double)L_CAP; |
| } |
| } |
|
|
| bool try_add_with_removal(const vector<Item>& items, Solution& sol, int i) { |
| const Item& it = items[i]; |
| if (sol.x[i] >= it.q) return false; |
|
|
| |
| if (it.m > M_CAP || it.l > L_CAP) return false; |
|
|
| |
| bool improved = false; |
| |
| int tryLimit = 100000; |
| while (sol.x[i] < it.q && tryLimit-- > 0) { |
| if (it.m <= sol.remM && it.l <= sol.remL) { |
| sol.x[i] += 1; |
| sol.remM -= it.m; |
| sol.remL -= it.l; |
| sol.val += it.v; |
| improved = true; |
| continue; |
| } |
| long long needM = max(0LL, it.m - sol.remM); |
| long long needL = max(0LL, it.l - sol.remL); |
| if (needM <= 0 && needL <= 0) { |
| |
| sol.x[i] += 1; |
| sol.remM -= it.m; |
| sol.remL -= it.l; |
| sol.val += it.v; |
| improved = true; |
| continue; |
| } |
|
|
| |
| struct Cand { int idx; double ratio; }; |
| vector<Cand> cands; |
| double alpha = (double)needM; |
| double beta = (double)needL; |
| for (int j = 0; j < (int)items.size(); ++j) { |
| if (sol.x[j] <= 0) continue; |
| double denom = alpha * (double)items[j].m + beta * (double)items[j].l; |
| if (denom <= 0) continue; |
| double r = (double)items[j].v / denom; |
| cands.push_back({j, r}); |
| } |
| if (cands.empty()) { |
| |
| break; |
| } |
| sort(cands.begin(), cands.end(), [](const Cand& a, const Cand& b){ |
| if (a.ratio == b.ratio) return a.idx < b.idx; |
| return a.ratio < b.ratio; |
| }); |
|
|
| long long freedM = 0, freedL = 0; |
| long long removedValue = 0; |
| vector<pair<int,long long>> plan; |
| long long needM_left = needM; |
| long long needL_left = needL; |
|
|
| for (auto &c : cands) { |
| if (needM_left <= 0 && needL_left <= 0) break; |
| int j = c.idx; |
| long long have = sol.x[j]; |
| if (have <= 0) continue; |
| long long mj = items[j].m; |
| long long lj = items[j].l; |
|
|
| |
| long long tM = (needM_left > 0 && mj > 0) ? ( (needM_left + mj - 1) / mj ) : 0; |
| long long tL = (needL_left > 0 && lj > 0) ? ( (needL_left + lj - 1) / lj ) : 0; |
| long long t = max(tM, tL); |
| if (t <= 0) continue; |
| if (t > have) t = have; |
|
|
| freedM += t * mj; |
| freedL += t * lj; |
| removedValue += t * items[j].v; |
| plan.push_back({j, t}); |
|
|
| |
| if (freedM >= needM) needM_left = 0; |
| else needM_left = needM - freedM; |
| if (freedL >= needL) needL_left = 0; |
| else needL_left = needL - freedL; |
| } |
|
|
| if (needM_left > 0 || needL_left > 0) { |
| |
| break; |
| } |
|
|
| if (it.v > removedValue) { |
| |
| for (auto &pr : plan) { |
| int j = pr.first; |
| long long t = pr.second; |
| sol.x[j] -= t; |
| sol.remM += t * items[j].m; |
| sol.remL += t * items[j].l; |
| sol.val -= t * items[j].v; |
| } |
| |
| sol.x[i] += 1; |
| sol.remM -= it.m; |
| sol.remL -= it.l; |
| sol.val += it.v; |
| improved = true; |
| continue; |
| } else { |
| |
| break; |
| } |
| } |
| return improved; |
| } |
|
|
| void improve_solution(const vector<Item>& items, Solution& sol, double time_limit_sec) { |
| auto t0 = chrono::steady_clock::now(); |
| int n = (int)items.size(); |
|
|
| |
| auto norm_metric = [&](const Item& it)->double { |
| double denom = it.nm + it.nl; |
| if (denom <= 0) denom = 1e-12; |
| return (double)it.v / denom; |
| }; |
| vector<int> order = order_by_metric(items, norm_metric); |
|
|
| while (true) { |
| auto t1 = chrono::steady_clock::now(); |
| double elapsed = chrono::duration<double>(t1 - t0).count(); |
| if (elapsed > time_limit_sec) break; |
|
|
| bool any = false; |
|
|
| |
| for (int idx = 0; idx < n; ++idx) { |
| int i = order[idx]; |
| bool changed = try_add_with_removal(items, sol, i); |
| if (changed) any = true; |
|
|
| auto t2 = chrono::steady_clock::now(); |
| double elapsed2 = chrono::duration<double>(t2 - t0).count(); |
| if (elapsed2 > time_limit_sec) break; |
| } |
|
|
| if (!any) break; |
| } |
| } |
|
|
| int main() { |
| ios::sync_with_stdio(false); |
| cin.tie(nullptr); |
|
|
| |
| string input, line; |
| { |
| ostringstream oss; |
| string tmp; |
| while (getline(cin, tmp)) { |
| oss << tmp << '\n'; |
| } |
| input = oss.str(); |
| } |
|
|
| vector<Item> items; |
| try { |
| Parser parser(input); |
| items = parser.parseItems(); |
| } catch (...) { |
| |
| |
| |
| } |
|
|
| int n = (int)items.size(); |
| init_norms(items); |
|
|
| |
| vector<vector<int>> orders; |
|
|
| |
| vector<double> lambdas = {0.0, 0.2, 0.5, 0.8, 1.0}; |
| for (double lam : lambdas) { |
| auto metric = [lam](const Item& it)->double { |
| double denom = lam * it.nm + (1.0 - lam) * it.nl; |
| if (denom <= 0) denom = 1e-12; |
| return (double)it.v / denom; |
| }; |
| orders.push_back(order_by_metric(items, metric)); |
| } |
|
|
| |
| orders.push_back(order_by_metric(items, [](const Item& it)->double { |
| double denom = (double)it.m; |
| if (denom <= 0) denom = 1e-12; |
| return (double)it.v / denom; |
| })); |
| |
| orders.push_back(order_by_metric(items, [](const Item& it)->double { |
| double denom = (double)it.l; |
| if (denom <= 0) denom = 1e-12; |
| return (double)it.v / denom; |
| })); |
| |
| orders.push_back(order_by_metric(items, [](const Item& it)->double { |
| double denom = it.nm + it.nl; |
| if (denom <= 0) denom = 1e-12; |
| return (double)it.v / denom; |
| })); |
| |
| orders.push_back(order_by_metric(items, [](const Item& it)->double { |
| double denom = max(it.nm, it.nl); |
| if (denom <= 0) denom = 1e-12; |
| return (double)it.v / denom; |
| })); |
| |
| orders.push_back(order_by_metric(items, [](const Item& it)->double { |
| double denom = hypot(it.nm, it.nl); |
| if (denom <= 0) denom = 1e-12; |
| return (double)it.v / denom; |
| })); |
| |
| orders.push_back(order_by_metric(items, [](const Item& it)->double { |
| return (double)it.v; |
| })); |
|
|
| |
| Solution best; |
| best.x.assign(n, 0); |
| best.val = -1; |
| best.remM = M_CAP; |
| best.remL = L_CAP; |
|
|
| for (auto &ord : orders) { |
| Solution sol = greedy_with_order(items, ord); |
| if (sol.val > best.val) best = sol; |
| } |
|
|
| |
| improve_solution(items, best, 0.85); |
|
|
| |
| cout << "{\n"; |
| for (int i = 0; i < n; ++i) { |
| cout << " \"" << items[i].name << "\": " << (best.x[i] < 0 ? 0 : best.x[i]); |
| if (i + 1 < n) cout << ",\n"; |
| else cout << "\n"; |
| } |
| cout << "}\n"; |
| return 0; |
| } |