| #include <bits/stdc++.h> |
| using namespace std; |
|
|
| struct Type { |
| string name; |
| long long q; |
| long long v; |
| long long m; |
| long long l; |
| }; |
|
|
| struct PItem { |
| int type; |
| int mult; |
| long long val; |
| int wM; |
| int wL; |
| }; |
|
|
| static const long long MASS_CAP = 20000000LL; |
| static const long long VOL_CAP = 25000000LL; |
|
|
| |
| vector<Type> parseInput(istream& in) { |
| string s((istreambuf_iterator<char>(in)), istreambuf_iterator<char>()); |
| vector<Type> items; |
| size_t i = 0, n = s.size(); |
|
|
| auto skip_ws = [&]() { |
| while (i < n && isspace((unsigned char)s[i])) i++; |
| }; |
| auto skip_until = [&](char c){ |
| while (i < n && s[i] != c) i++; |
| if (i < n && s[i] == c) i++; |
| }; |
| auto parse_string = [&]() -> string { |
| skip_ws(); |
| while (i < n && s[i] != '"') i++; |
| if (i < n && s[i] == '"') i++; |
| string res; |
| while (i < n && s[i] != '"') { |
| if (s[i] == '\\' && i + 1 < n) { |
| res.push_back(s[i+1]); |
| i += 2; |
| } else { |
| res.push_back(s[i++]); |
| } |
| } |
| if (i < n && s[i] == '"') i++; |
| return res; |
| }; |
| auto parse_ll = [&]() -> long long { |
| skip_ws(); |
| |
| while (i < n && !(s[i] == '-' || (s[i] >= '0' && s[i] <= '9'))) i++; |
| long long sign = 1; |
| if (i < n && s[i] == '-') { sign = -1; i++; } |
| long long val = 0; |
| while (i < n && s[i] >= '0' && s[i] <= '9') { |
| val = val * 10 + (s[i] - '0'); |
| i++; |
| } |
| return sign * val; |
| }; |
|
|
| skip_ws(); |
| |
| while (i < n && s[i] != '{') i++; |
| if (i < n && s[i] == '{') i++; |
|
|
| while (true) { |
| skip_ws(); |
| if (i >= n) break; |
| if (s[i] == '}') { i++; break; } |
| string key = parse_string(); |
| skip_ws(); |
| |
| while (i < n && s[i] != '[') i++; |
| if (i < n && s[i] == '[') i++; |
| long long q = parse_ll(); |
| long long v = parse_ll(); |
| long long m = parse_ll(); |
| long long l = parse_ll(); |
| |
| while (i < n && s[i] != ']') i++; |
| if (i < n && s[i] == ']') i++; |
| items.push_back({key, q, v, m, l}); |
| |
| while (i < n && s[i] != '"' && s[i] != '}') i++; |
| if (i < n && s[i] == '}') { i++; break; } |
| } |
| return items; |
| } |
|
|
| struct Solution { |
| vector<long long> cnt; |
| long long value; |
| long long mass; |
| long long vol; |
| }; |
|
|
| static inline long long clampLL(long long x, long long lo, long long hi) { |
| if (x < lo) return lo; |
| if (x > hi) return hi; |
| return x; |
| } |
|
|
| Solution evalSolution(const vector<Type>& types, const vector<long long>& cnt) { |
| long long mass=0, vol=0, val=0; |
| int n = (int)types.size(); |
| for (int i=0;i<n;i++) { |
| long long c = cnt[i]; |
| if (c < 0) c = 0; |
| if (c > types[i].q) c = types[i].q; |
| mass += types[i].m * c; |
| vol += types[i].l * c; |
| val += types[i].v * c; |
| } |
| |
| if (mass > MASS_CAP || vol > VOL_CAP) { |
| |
| return Solution{vector<long long>(n,0),0,0,0}; |
| } |
| return Solution{cnt, val, mass, vol}; |
| } |
|
|
| Solution greedyFill(const vector<Type>& types, const vector<long long>& base, double lambda) { |
| int n = (int)types.size(); |
| vector<long long> cnt = base; |
| long long mass=0, vol=0, val=0; |
| for (int i=0;i<n;i++) { |
| long long c = clampLL(cnt[i], 0, types[i].q); |
| cnt[i] = c; |
| mass += types[i].m * c; |
| vol += types[i].l * c; |
| val += types[i].v * c; |
| } |
| long long remM = MASS_CAP - mass; |
| long long remL = VOL_CAP - vol; |
| if (remM < 0 || remL < 0) { |
| |
| return evalSolution(types, cnt); |
| } |
|
|
| while (true) { |
| int best = -1; |
| double bestScore = -1.0; |
| for (int i=0;i<n;i++) { |
| if (cnt[i] >= types[i].q) continue; |
| if (types[i].m > remM || types[i].l > remL) continue; |
| double normM = (double)types[i].m / (double)MASS_CAP; |
| double normL = (double)types[i].l / (double)VOL_CAP; |
| double denom = lambda * normM + (1.0 - lambda) * normL; |
| if (denom <= 0) continue; |
| double score = (double)types[i].v / denom; |
| if (score > bestScore) { bestScore = score; best = i; } |
| } |
| if (best == -1) break; |
| long long canM = remM / types[best].m; |
| long long canL = remL / types[best].l; |
| long long canQ = types[best].q - cnt[best]; |
| long long add = min(canQ, min(canM, canL)); |
| if (add <= 0) break; |
| cnt[best] += add; |
| remM -= add * types[best].m; |
| remL -= add * types[best].l; |
| val += add * types[best].v; |
| } |
| return evalSolution(types, cnt); |
| } |
|
|
| Solution greedyMaxRatio(const vector<Type>& types) { |
| int n = (int)types.size(); |
| vector<int> ord(n); |
| iota(ord.begin(), ord.end(), 0); |
| vector<double> ratio(n, 0.0); |
| for (int i=0;i<n;i++) { |
| double a = (double)types[i].m / (double)MASS_CAP; |
| double b = (double)types[i].l / (double)VOL_CAP; |
| double d = max(a, b); |
| if (d <= 0) ratio[i] = 0; |
| else ratio[i] = (double)types[i].v / d; |
| } |
| sort(ord.begin(), ord.end(), [&](int a, int b){ |
| if (ratio[a] != ratio[b]) return ratio[a] > ratio[b]; |
| return types[a].v > types[b].v; |
| }); |
|
|
| vector<long long> cnt(n, 0); |
| long long remM = MASS_CAP, remL = VOL_CAP; |
| for (int id : ord) { |
| if (types[id].m > remM || types[id].l > remL) continue; |
| long long k = min((long long)types[id].q, min(remM / types[id].m, remL / types[id].l)); |
| if (k > 0) { |
| cnt[id] = k; |
| remM -= k * types[id].m; |
| remL -= k * types[id].l; |
| } |
| } |
| return evalSolution(types, cnt); |
| } |
|
|
| Solution solveDPScaled(const vector<Type>& types, long long scaleM, long long scaleL) { |
| int n = (int)types.size(); |
| long long Msc = MASS_CAP / scaleM; |
| long long Lsc = VOL_CAP / scaleL; |
| int MS = (int)Msc; |
| int LS = (int)Lsc; |
| if (MS <= 0 || LS <= 0) { |
| vector<long long> zero(n,0); |
| return evalSolution(types, zero); |
| } |
|
|
| |
| vector<PItem> items; |
| items.reserve(200); |
| for (int i=0;i<n;i++) { |
| long long qcap = min(types[i].q, min(MASS_CAP / max(1LL, types[i].m), VOL_CAP / max(1LL, types[i].l))); |
| long long j = 1; |
| long long Q = qcap; |
| while (Q > 0) { |
| long long chunk = min(j, Q); |
| long long tm = types[i].m * chunk; |
| long long tl = types[i].l * chunk; |
| int wM = (int)((tm + scaleM - 1) / scaleM); |
| int wL = (int)((tl + scaleL - 1) / scaleL); |
| if (wM <= MS && wL <= LS) { |
| items.push_back({i, (int)chunk, types[i].v * chunk, wM, wL}); |
| } |
| Q -= chunk; |
| j <<= 1; |
| } |
| } |
|
|
| int W = (LS + 1); |
| int SZ = (MS + 1) * W; |
|
|
| |
| vector<long long> dp(SZ, 0); |
| vector<int> prevItem(SZ, -1); |
| vector<int> prevIdx(SZ, -1); |
|
|
| for (int idxItem = 0; idxItem < (int)items.size(); idxItem++) { |
| const PItem &p = items[idxItem]; |
| for (int m = MS; m >= p.wM; --m) { |
| int base_m = m * W; |
| int prev_m = (m - p.wM) * W; |
| for (int v = LS; v >= p.wL; --v) { |
| int idx = base_m + v; |
| int pidx = prev_m + (v - p.wL); |
| long long cand = dp[pidx] + p.val; |
| if (cand > dp[idx]) { |
| dp[idx] = cand; |
| prevItem[idx] = idxItem; |
| prevIdx[idx] = pidx; |
| } |
| } |
| } |
| } |
|
|
| |
| long long bestVal = -1; |
| int bestState = 0; |
| for (int i=0;i<SZ;i++) { |
| if (dp[i] > bestVal) { bestVal = dp[i]; bestState = i; } |
| } |
|
|
| vector<long long> cnt(n, 0); |
| int cur = bestState; |
| while (cur >= 0 && prevItem[cur] != -1) { |
| int it = prevItem[cur]; |
| cnt[items[it].type] += items[it].mult; |
| cur = prevIdx[cur]; |
| } |
|
|
| |
| for (int i=0;i<n;i++) { |
| cnt[i] = clampLL(cnt[i], 0, types[i].q); |
| } |
|
|
| Solution sol = evalSolution(types, cnt); |
|
|
| |
| vector<double> lambdas = {0.0, 0.33, 0.5, 0.67, 1.0}; |
| Solution best = sol; |
| for (double lam : lambdas) { |
| Solution s2 = greedyFill(types, sol.cnt, lam); |
| if (s2.value > best.value) best = s2; |
| } |
| return best; |
| } |
|
|
| Solution greedyMulti(const vector<Type>& types) { |
| vector<double> lambdas = {0.0, 0.25, 0.5, 0.75, 1.0}; |
| Solution best{{},0,0,0}; |
| int n = (int)types.size(); |
| for (double lam : lambdas) { |
| vector<int> ord(n); |
| iota(ord.begin(), ord.end(), 0); |
| vector<double> ratio(n, 0.0); |
| for (int i=0;i<n;i++) { |
| double normM = (double)types[i].m / (double)MASS_CAP; |
| double normL = (double)types[i].l / (double)VOL_CAP; |
| double denom = lam * normM + (1.0 - lam) * normL; |
| if (denom <= 0) ratio[i] = 0; |
| else ratio[i] = (double)types[i].v / denom; |
| } |
| sort(ord.begin(), ord.end(), [&](int a, int b){ |
| if (ratio[a] != ratio[b]) return ratio[a] > ratio[b]; |
| return types[a].v > types[b].v; |
| }); |
|
|
| vector<long long> cnt(n, 0); |
| long long remM = MASS_CAP, remL = VOL_CAP; |
| for (int id : ord) { |
| if (types[id].m > remM || types[id].l > remL) continue; |
| long long add = min((long long)types[id].q, min(remM / types[id].m, remL / types[id].l)); |
| if (add > 0) { |
| cnt[id] = add; |
| remM -= add * types[id].m; |
| remL -= add * types[id].l; |
| } |
| } |
| Solution s = evalSolution(types, cnt); |
| if (s.value > best.value) best = s; |
| } |
| Solution smax = greedyMaxRatio(types); |
| if (smax.value > best.value) best = smax; |
| return best; |
| } |
|
|
| Solution pairwiseImprove(const vector<Type>& types, Solution sol) { |
| int n = (int)types.size(); |
| vector<long long> cnt = sol.cnt; |
| long long mass = sol.mass, vol = sol.vol, val = sol.value; |
| bool improved = true; |
| int iter = 0; |
| while (improved && iter < 200) { |
| improved = false; |
| iter++; |
| for (int i=0;i<n && !improved;i++) { |
| if (cnt[i] >= types[i].q) continue; |
| for (int j=0;j<n && !improved;j++) { |
| if (cnt[j] <= 0) continue; |
| if (i == j) continue; |
| long long nmass = mass + types[i].m - types[j].m; |
| long long nvol = vol + types[i].l - types[j].l; |
| if (nmass <= MASS_CAP && nvol <= VOL_CAP && types[i].v > types[j].v) { |
| mass = nmass; vol = nvol; val += (types[i].v - types[j].v); |
| cnt[i]++; cnt[j]--; |
| improved = true; |
| } |
| } |
| } |
| } |
| return evalSolution(types, cnt); |
| } |
|
|
| int main() { |
| ios::sync_with_stdio(false); |
| cin.tie(nullptr); |
|
|
| vector<Type> types = parseInput(cin); |
| int n = (int)types.size(); |
| |
| for (int i=0;i<n;i++) { |
| long long capM = (types[i].m > 0) ? MASS_CAP / types[i].m : 0; |
| long long capL = (types[i].l > 0) ? VOL_CAP / types[i].l : 0; |
| long long qcap = min(types[i].q, min(capM, capL)); |
| types[i].q = max(0LL, qcap); |
| } |
|
|
| |
| vector<pair<long long,long long>> scales = { |
| {100000, 125000}, |
| {100000, 100000}, |
| {50000, 125000}, |
| {200000, 125000}, |
| }; |
|
|
| Solution best{{},0,0,0}; |
|
|
| |
| Solution g = greedyMulti(types); |
| if (g.value > best.value) best = g; |
|
|
| |
| for (auto sc : scales) { |
| Solution s = solveDPScaled(types, sc.first, sc.second); |
| if (s.value > best.value) best = s; |
| } |
|
|
| |
| Solution improved = pairwiseImprove(types, best); |
| if (improved.value > best.value) best = improved; |
|
|
| |
| cout << "{\n"; |
| for (int i=0;i<n;i++) { |
| cout << " \"" << types[i].name << "\": " << clampLL(best.cnt[i], 0, types[i].q); |
| if (i + 1 < n) cout << ",\n"; |
| else cout << "\n"; |
| } |
| cout << "}\n"; |
| return 0; |
| } |