| #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 skipWS() { |
| while (pos < s.size() && isspace((unsigned char)s[pos])) pos++; |
| } |
|
|
| bool match(char c) { |
| skipWS(); |
| if (pos < s.size() && s[pos] == c) { |
| pos++; |
| return true; |
| } |
| return false; |
| } |
|
|
| void expect(char c) { |
| skipWS(); |
| if (pos >= s.size() || s[pos] != c) { |
| |
| |
| |
| pos = s.size(); |
| return; |
| } |
| pos++; |
| } |
|
|
| string parseString() { |
| skipWS(); |
| string res; |
| if (pos < s.size() && s[pos] == '"') { |
| pos++; |
| while (pos < s.size()) { |
| char c = s[pos++]; |
| if (c == '\\') { |
| if (pos < s.size()) { |
| char next = s[pos++]; |
| |
| if (next == '"' || next == '\\' || next == '/') res.push_back(next); |
| else if (next == 'b') res.push_back('\b'); |
| else if (next == 'f') res.push_back('\f'); |
| else if (next == 'n') res.push_back('\n'); |
| else if (next == 'r') res.push_back('\r'); |
| else if (next == 't') res.push_back('\t'); |
| else res.push_back(next); |
| } |
| } else if (c == '"') { |
| break; |
| } else { |
| res.push_back(c); |
| } |
| } |
| } |
| return res; |
| } |
|
|
| long long parseInt() { |
| skipWS(); |
| bool neg = false; |
| if (pos < s.size() && (s[pos] == '-' || s[pos] == '+')) { |
| neg = (s[pos] == '-'); |
| pos++; |
| } |
| long long val = 0; |
| while (pos < s.size() && isdigit((unsigned char)s[pos])) { |
| val = val * 10 + (s[pos] - '0'); |
| pos++; |
| } |
| return neg ? -val : val; |
| } |
|
|
| vector<Item> parse() { |
| vector<Item> items; |
| expect('{'); |
| while (true) { |
| skipWS(); |
| if (pos >= s.size()) break; |
| if (s[pos] == '}') { pos++; break; } |
| string key = parseString(); |
| expect(':'); |
| |
| expect('['); |
| long long q = parseInt(); expect(','); |
| long long v = parseInt(); expect(','); |
| long long m = parseInt(); expect(','); |
| long long l = parseInt(); |
| expect(']'); |
| Item it; |
| it.name = key; it.q = q; it.v = v; it.m = m; it.l = l; |
| it.idx = (int)items.size(); |
| items.push_back(it); |
| skipWS(); |
| if (pos < s.size() && s[pos] == ',') pos++; |
| } |
| return items; |
| } |
| }; |
|
|
| struct Solution { |
| vector<long long> cnt; |
| long long val=0, usedM=0, usedL=0; |
| }; |
|
|
| static const long long CAP_M = 20000000LL; |
| static const long long CAP_L = 25000000LL; |
|
|
| struct HeuristicSolver { |
| vector<Item> items; |
| int n; |
| vector<long long> qLim; |
|
|
| HeuristicSolver(const vector<Item>& its) : items(its) { |
| n = (int)items.size(); |
| qLim.resize(n); |
| for (int i = 0; i < n; ++i) { |
| long long qm = items[i].m > 0 ? (CAP_M / items[i].m) : 0; |
| long long ql = items[i].l > 0 ? (CAP_L / items[i].l) : 0; |
| qLim[i] = min(items[i].q, min(qm, ql)); |
| } |
| } |
|
|
| Solution evaluate(const vector<long long>& cnt) { |
| Solution s; |
| s.cnt = cnt; |
| long long M=0, L=0, V=0; |
| for (int i = 0; i < n; ++i) { |
| long long c = cnt[i]; |
| if (c < 0) { s.val = -1; return s; } |
| if (c > qLim[i]) { s.val = -1; return s; } |
| V += c * items[i].v; |
| M += c * items[i].m; |
| L += c * items[i].l; |
| } |
| if (M > CAP_M || L > CAP_L) { s.val = -1; return s; } |
| s.val = V; s.usedM = M; s.usedL = L; |
| return s; |
| } |
|
|
| vector<int> sorted_by_ratio(double alpha) { |
| vector<pair<double,int>> arr; |
| arr.reserve(n); |
| for (int i = 0; i < n; ++i) { |
| double cm = (double)items[i].m / (double)CAP_M; |
| double cl = (double)items[i].l / (double)CAP_L; |
| double denom = alpha * cm + (1.0 - alpha) * cl; |
| double ratio = (denom > 0) ? ( (double)items[i].v / denom ) : 1e300; |
| arr.emplace_back(ratio, i); |
| } |
| sort(arr.begin(), arr.end(), [&](auto& a, auto& b){ |
| if (a.first != b.first) return a.first > b.first; |
| |
| const Item &ia = items[a.second], &ib = items[b.second]; |
| if (ia.v != ib.v) return ia.v > ib.v; |
| long long sa = ia.m + ia.l, sb = ib.m + ib.l; |
| return sa < sb; |
| }); |
| vector<int> order; order.reserve(n); |
| for (auto &p : arr) order.push_back(p.second); |
| return order; |
| } |
|
|
| vector<int> sorted_by_maxnorm() { |
| vector<pair<double,int>> arr; |
| arr.reserve(n); |
| for (int i = 0; i < n; ++i) { |
| double cnm = (double)items[i].m / (double)CAP_M; |
| double cnl = (double)items[i].l / (double)CAP_L; |
| double denom = max(cnm, cnl); |
| double ratio = (denom > 0) ? ((double)items[i].v / denom) : 1e300; |
| arr.emplace_back(ratio, i); |
| } |
| sort(arr.begin(), arr.end(), [&](auto& a, auto& b){ |
| if (a.first != b.first) return a.first > b.first; |
| const Item &ia = items[a.second], &ib = items[b.second]; |
| if (ia.v != ib.v) return ia.v > ib.v; |
| long long sa = ia.m + ia.l, sb = ib.m + ib.l; |
| return sa < sb; |
| }); |
| vector<int> order; order.reserve(n); |
| for (auto &p : arr) order.push_back(p.second); |
| return order; |
| } |
|
|
| vector<long long> fill_sorted_order(const vector<int>& order) { |
| vector<long long> cnt(n, 0); |
| long long RM = CAP_M, RL = CAP_L; |
| for (int idx : order) { |
| if (qLim[idx] <= 0) continue; |
| long long cm = items[idx].m, cl = items[idx].l; |
| if (cm == 0 || cl == 0) continue; |
| long long canM = RM / cm; |
| long long canL = RL / cl; |
| long long add = min(qLim[idx] - cnt[idx], min(canM, canL)); |
| if (add <= 0) continue; |
| cnt[idx] += add; |
| RM -= add * cm; |
| RL -= add * cl; |
| } |
| return cnt; |
| } |
|
|
| vector<long long> fill_incremental_static_ratio(double alpha, vector<long long> startCnt = {}) { |
| vector<long long> cnt = startCnt.empty() ? vector<long long>(n, 0) : startCnt; |
| long long usedM = 0, usedL = 0; |
| if (!startCnt.empty()) { |
| for (int i = 0; i < n; ++i) { |
| usedM += cnt[i] * items[i].m; |
| usedL += cnt[i] * items[i].l; |
| } |
| } |
| long long RM = CAP_M - usedM, RL = CAP_L - usedL; |
| if (RM < 0 || RL < 0) return cnt; |
|
|
| |
| vector<double> score(n, -1e300); |
| for (int i = 0; i < n; ++i) { |
| double cm = (double)items[i].m / (double)CAP_M; |
| double cl = (double)items[i].l / (double)CAP_L; |
| double denom = alpha * cm + (1.0 - alpha) * cl; |
| score[i] = (denom > 0) ? ((double)items[i].v / denom) : 1e300; |
| } |
|
|
| while (true) { |
| int best = -1; |
| double bestScore = -1e300; |
| for (int i = 0; i < n; ++i) { |
| if (cnt[i] >= qLim[i]) continue; |
| if (items[i].m <= RM && items[i].l <= RL) { |
| double sc = score[i]; |
| if (sc > bestScore) { |
| bestScore = sc; best = i; |
| } |
| } |
| } |
| if (best == -1) break; |
| cnt[best] += 1; |
| RM -= items[best].m; |
| RL -= items[best].l; |
| } |
| return cnt; |
| } |
|
|
| vector<long long> fill_incremental_dynamic_ratio(vector<long long> startCnt = {}) { |
| vector<long long> cnt = startCnt.empty() ? vector<long long>(n, 0) : startCnt; |
| long long usedM = 0, usedL = 0; |
| if (!startCnt.empty()) { |
| for (int i = 0; i < n; ++i) { |
| usedM += cnt[i] * items[i].m; |
| usedL += cnt[i] * items[i].l; |
| } |
| } |
| long long RM = CAP_M - usedM, RL = CAP_L - usedL; |
| if (RM < 0 || RL < 0) return cnt; |
|
|
| while (true) { |
| int best = -1; |
| double bestScore = -1e300; |
| double wm = (RM > 0) ? (1.0 / (double)RM) : 1e300; |
| double wl = (RL > 0) ? (1.0 / (double)RL) : 1e300; |
| for (int i = 0; i < n; ++i) { |
| if (cnt[i] >= qLim[i]) continue; |
| if (items[i].m <= RM && items[i].l <= RL) { |
| double denom = items[i].m * wm + items[i].l * wl; |
| double sc = denom > 0 ? ((double)items[i].v / denom) : 1e300; |
| if (sc > bestScore) { |
| bestScore = sc; best = i; |
| } |
| } |
| } |
| if (best == -1) break; |
| cnt[best] += 1; |
| RM -= items[best].m; |
| RL -= items[best].l; |
| } |
| return cnt; |
| } |
|
|
| Solution best_of_candidates(const vector<vector<long long>>& cands) { |
| Solution best; |
| best.val = -1; |
| for (auto &cnt : cands) { |
| Solution s = evaluate(cnt); |
| if (s.val > best.val) best = s; |
| } |
| if (best.val < 0) { |
| |
| best = evaluate(vector<long long>(n,0)); |
| } |
| return best; |
| } |
|
|
| vector<long long> greedy_refill(vector<long long> cnt, long long RM, long long RL, double alpha) { |
| |
| |
| |
| vector<double> score(n, -1e300); |
| for (int i = 0; i < n; ++i) { |
| double cm = (double)items[i].m / (double)CAP_M; |
| double cl = (double)items[i].l / (double)CAP_L; |
| double denom = alpha * cm + (1.0 - alpha) * cl; |
| score[i] = (denom > 0) ? ((double)items[i].v / denom) : 1e300; |
| } |
| while (true) { |
| int best = -1; |
| double bestScore = -1e300; |
| for (int i = 0; i < n; ++i) { |
| if (cnt[i] >= qLim[i]) continue; |
| if (items[i].m <= RM && items[i].l <= RL) { |
| double sc = score[i]; |
| if (sc > bestScore) { |
| bestScore = sc; best = i; |
| } |
| } |
| } |
| if (best == -1) break; |
| cnt[best] += 1; |
| RM -= items[best].m; |
| RL -= items[best].l; |
| } |
| return cnt; |
| } |
|
|
| Solution local_improve(Solution start) { |
| vector<long long> cnt = start.cnt; |
| long long usedM = start.usedM, usedL = start.usedL; |
| long long bestVal = start.val; |
|
|
| int maxPasses = 2; |
| int Kremove = 8; |
|
|
| for (int pass = 0; pass < maxPasses; ++pass) { |
| bool improved = false; |
| |
| vector<int> idxs(n); |
| iota(idxs.begin(), idxs.end(), 0); |
| sort(idxs.begin(), idxs.end(), [&](int a, int b){ |
| if (cnt[a] != cnt[b]) return cnt[a] > cnt[b]; |
| return items[a].v > items[b].v; |
| }); |
|
|
| for (int ii = 0; ii < n; ++ii) { |
| int i = idxs[ii]; |
| if (cnt[i] <= 0) continue; |
| int maxK = (int)min<long long>(cnt[i], Kremove); |
| for (int k = 1; k <= maxK; ++k) { |
| vector<long long> tmp = cnt; |
| tmp[i] -= k; |
| long long RM = usedM + k * items[i].m; |
| long long RL = usedL + k * items[i].l; |
| |
| vector<double> alphas = {0.0, 0.5, 1.0}; |
| long long bestLocalVal = -1; |
| vector<long long> bestLocalCnt; |
| for (double a : alphas) { |
| vector<long long> filled = greedy_refill(tmp, RM, RL, a); |
| Solution s = evaluate(filled); |
| if (s.val > bestLocalVal) { |
| bestLocalVal = s.val; |
| bestLocalCnt = move(filled); |
| } |
| } |
| if (bestLocalVal > bestVal) { |
| |
| Solution s = evaluate(bestLocalCnt); |
| cnt = move(bestLocalCnt); |
| usedM = s.usedM; usedL = s.usedL; bestVal = s.val; |
| improved = true; |
| break; |
| } |
| } |
| if (improved) break; |
| } |
| if (!improved) break; |
| } |
|
|
| Solution res = evaluate(cnt); |
| return res; |
| } |
|
|
| Solution solve() { |
| vector<vector<long long>> candidates; |
| candidates.reserve(64); |
|
|
| |
| vector<double> alphas = {0.0, 0.1, 0.2, 0.25, 0.3, 0.4, 0.5, 0.6, 0.7, 0.75, 0.8, 0.9, 1.0}; |
| for (double a : alphas) { |
| auto order = sorted_by_ratio(a); |
| candidates.push_back(fill_sorted_order(order)); |
| candidates.push_back(fill_incremental_static_ratio(a)); |
| } |
|
|
| |
| auto ord_max = sorted_by_maxnorm(); |
| candidates.push_back(fill_sorted_order(ord_max)); |
| |
| candidates.push_back(fill_incremental_dynamic_ratio()); |
|
|
| |
| { |
| vector<int> order(n); |
| iota(order.begin(), order.end(), 0); |
| sort(order.begin(), order.end(), [&](int i, int j){ |
| if (items[i].v != items[j].v) return items[i].v > items[j].v; |
| long long si = items[i].m + items[i].l, sj = items[j].m + items[j].l; |
| return si < sj; |
| }); |
| candidates.push_back(fill_sorted_order(order)); |
| } |
| |
| { |
| vector<pair<double,int>> arr; |
| for (int i=0;i<n;++i){ |
| double eff = (items[i].m>0)? (double)items[i].v / (double)items[i].m : 1e300; |
| arr.emplace_back(eff,i); |
| } |
| sort(arr.begin(), arr.end(), [&](auto&a, auto&b){ |
| if (a.first != b.first) return a.first > b.first; |
| return items[a.second].v > items[b.second].v; |
| }); |
| vector<int> order; order.reserve(n); |
| for (auto &p:arr) order.push_back(p.second); |
| candidates.push_back(fill_sorted_order(order)); |
| } |
| |
| { |
| vector<pair<double,int>> arr; |
| for (int i=0;i<n;++i){ |
| double eff = (items[i].l>0)? (double)items[i].v / (double)items[i].l : 1e300; |
| arr.emplace_back(eff,i); |
| } |
| sort(arr.begin(), arr.end(), [&](auto&a, auto&b){ |
| if (a.first != b.first) return a.first > b.first; |
| return items[a.second].v > items[b.second].v; |
| }); |
| vector<int> order; order.reserve(n); |
| for (auto &p:arr) order.push_back(p.second); |
| candidates.push_back(fill_sorted_order(order)); |
| } |
|
|
| Solution best = best_of_candidates(candidates); |
|
|
| |
| best = local_improve(best); |
|
|
| return best; |
| } |
| }; |
|
|
| int main() { |
| ios::sync_with_stdio(false); |
| cin.tie(nullptr); |
|
|
| string input; |
| { |
| ostringstream oss; |
| oss << cin.rdbuf(); |
| input = oss.str(); |
| } |
|
|
| Parser parser(input); |
| vector<Item> items = parser.parse(); |
|
|
| |
| HeuristicSolver solver(items); |
| Solution best = solver.solve(); |
|
|
| |
| cout << "{\n"; |
| for (size_t i = 0; i < items.size(); ++i) { |
| cout << " \"" << items[i].name << "\": " << (best.cnt.size() > i ? best.cnt[i] : 0); |
| if (i + 1 < items.size()) cout << ",\n"; |
| else cout << "\n"; |
| } |
| cout << "}\n"; |
| return 0; |
| } |