| #include <bits/stdc++.h> |
| 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; |
| |
| 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<long long> read_array_numbers() { |
| vector<long long> nums; |
| skip_ws(); |
| if (!expect('[')) return nums; |
| while (true) { |
| skip_ws(); |
| |
| 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 { |
| |
| break; |
| } |
| } |
| return nums; |
| } |
| }; |
|
|
| int main() { |
| ios::sync_with_stdio(false); |
| cin.tie(nullptr); |
|
|
| |
| std::ostringstream oss; |
| oss << cin.rdbuf(); |
| string input = oss.str(); |
|
|
| Parser p(input); |
| const long long CAP_M = 20LL * 1000 * 1000; |
| const long long CAP_L = 25LL * 1000 * 1000; |
|
|
| vector<Item> items; |
| vector<string> order_names; |
|
|
| p.skip_ws(); |
| if (!p.expect('{')) { |
| |
| 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<long long> arr = p.read_array_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; |
| } |
| } |
|
|
| int n = (int)items.size(); |
| if (n == 0) { |
| cout << "{\n"; |
| |
| for (size_t i = 0; i < order_names.size(); ++i) { |
| cout << (i == 0 ? " " : ", ") << "\"" << order_names[i] << "\": 0\n"; |
| } |
| cout << "}\n"; |
| return 0; |
| } |
|
|
| |
| vector<long long> 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<int>& ord, |
| const vector<long long>& baseCounts, |
| long long usedM, long long usedL) { |
| vector<long long> 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; |
| 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<vector<long long>, long long>(x, val); |
| }; |
|
|
| auto greedy_fill = [&](const vector<int>& ord) { |
| vector<long long> base(n, 0); |
| return greedy_fill_with_order(ord, base, 0, 0); |
| }; |
|
|
| auto build_order_by_w = [&](double w) { |
| vector<pair<double,int>> dens; |
| dens.reserve(n); |
| for (int i = 0; i < n; ++i) { |
| |
| 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; |
| |
| 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<int> ord; |
| ord.reserve(n); |
| for (auto &pr : dens) ord.push_back(pr.second); |
| return ord; |
| }; |
|
|
| auto build_order_by_custom_desc = [&](const vector<double>& score) { |
| vector<int> 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<pair<double,int>> 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<int> ord; |
| for (auto &pr : arr) ord.push_back(pr.second); |
| return ord; |
| }; |
|
|
| vector<vector<int>> orders; |
|
|
| auto add_order_if_new = [&](const vector<int>& ord) { |
| for (auto &o : orders) { |
| if (o == ord) return; |
| } |
| orders.push_back(ord); |
| }; |
|
|
| |
| vector<double> 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)); |
|
|
| |
| { |
| vector<double> 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)); |
| } |
| |
| { |
| vector<double> 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)); |
| } |
| |
| { |
| vector<double> 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)); |
| } |
| |
| { |
| vector<double> 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)); |
| } |
| |
| add_order_if_new(build_order_small_size_first()); |
|
|
| |
| vector<long long> bestX(n, 0); |
| long long bestV = 0; |
| long long bestUsedM = 0, bestUsedL = 0; |
| vector<int> 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; |
| } |
| } |
|
|
| |
| auto start = chrono::steady_clock::now(); |
| auto elapsed_ms = [&]() { |
| return chrono::duration_cast<chrono::milliseconds>(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; |
| 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<long long>(4, bestX[i]); |
| for (long long r = 1; r <= max_remove && elapsed_ms() < time_limit_ms; ++r) { |
| vector<long long> 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; |
| if (curUsedL < 0) curUsedL = 0; |
|
|
| vector<int> dynOrd = build_dynamic_order(curUsedM, curUsedL); |
|
|
| |
| bool found = false; |
| for (int attempt = 0; attempt < 2; ++attempt) { |
| const vector<int>& 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) { |
| |
| 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; |
| } |
| } |
|
|
| |
| 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; |
| } |
| |
| 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) { |
| |
| vector<int> ord = build_order_by_w(0.5); |
| |
| 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; |
| } |
| } |
| } |
|
|
| |
| |
| unordered_map<string, long long> 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; |
| } |