| #include <bits/stdc++.h> |
| using namespace std; |
|
|
| struct Item { |
| string name; |
| long long q, v, m, l; |
| int idx; |
| }; |
|
|
| int main() { |
| ios::sync_with_stdio(false); |
| cin.tie(nullptr); |
| string input, line; |
| { |
| ostringstream ss; |
| ss << cin.rdbuf(); |
| input = ss.str(); |
| } |
|
|
| |
| regex re("\\\"([^\\\"]+)\\\"\\s*:\\s*\\[\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*\\]"); |
| sregex_iterator it(input.begin(), input.end(), re); |
| sregex_iterator end; |
| vector<Item> items; |
| int idx = 0; |
| for (; it != end; ++it) { |
| smatch m; |
| m = *it; |
| Item itx; |
| itx.name = m[1]; |
| itx.q = stoll(m[2]); |
| itx.v = stoll(m[3]); |
| itx.m = stoll(m[4]); |
| itx.l = stoll(m[5]); |
| itx.idx = idx++; |
| items.push_back(itx); |
| } |
| if (items.empty()) { |
| |
| cout << "{\n}\n"; |
| return 0; |
| } |
|
|
| const long long CAP_M = 20000000LL; |
| const long long CAP_L = 25000000LL; |
| int n = (int)items.size(); |
|
|
| auto greedy_by = [&](vector<double> density)->pair<vector<long long>, long long> { |
| vector<int> order(n); |
| iota(order.begin(), order.end(), 0); |
| stable_sort(order.begin(), order.end(), [&](int a, int b){ |
| if (density[a] == density[b]) return a < b; |
| return density[a] > density[b]; |
| }); |
| vector<long long> cnt(n, 0); |
| long long remM = CAP_M, remL = CAP_L; |
| long long totalV = 0; |
| for (int id : order) { |
| const Item &itx = items[id]; |
| if (itx.m == 0 || itx.l == 0) continue; |
| long long t1 = remM / itx.m; |
| long long t2 = remL / itx.l; |
| long long t = min({itx.q, t1, t2}); |
| if (t <= 0) continue; |
| cnt[id] += t; |
| remM -= t * itx.m; |
| remL -= t * itx.l; |
| totalV += t * itx.v; |
| } |
| return {cnt, totalV}; |
| }; |
|
|
| auto compute_density = [&](double lambda)->vector<double> { |
| vector<double> d(n); |
| for (int i = 0; i < n; ++i) { |
| double wm = (double)items[i].m / (double)CAP_M; |
| double wl = (double)items[i].l / (double)CAP_L; |
| double w = lambda * wm + (1.0 - lambda) * wl; |
| if (w == 0) w = 1e-18; |
| d[i] = (double)items[i].v / w; |
| } |
| return d; |
| }; |
|
|
| vector<pair<string,long long>> bestAns; bestAns.reserve(n); |
| vector<long long> bestCnt(n, 0); |
| long long bestV = -1; |
|
|
| |
| vector<double> lambdas = {0.0, 0.25, 0.5, 0.75, 1.0}; |
| for (double lam : lambdas) { |
| auto dens = compute_density(lam); |
| auto res = greedy_by(dens); |
| if (res.second > bestV) { |
| bestV = res.second; |
| bestCnt = move(res.first); |
| } |
| } |
| |
| { |
| vector<double> d(n); |
| for (int i = 0; i < n; ++i) { |
| double wm = (double)items[i].m / (double)CAP_M; |
| double wl = (double)items[i].l / (double)CAP_L; |
| double w = max(wm, wl); |
| if (w == 0) w = 1e-18; |
| d[i] = (double)items[i].v / w; |
| } |
| auto res = greedy_by(d); |
| if (res.second > bestV) { |
| bestV = res.second; |
| bestCnt = move(res.first); |
| } |
| } |
| |
| { |
| vector<double> d(n); |
| for (int i = 0; i < n; ++i) { |
| double w = (double)items[i].m / (double)CAP_M; |
| if (w == 0) w = 1e-18; |
| d[i] = (double)items[i].v / w; |
| } |
| auto res = greedy_by(d); |
| if (res.second > bestV) { |
| bestV = res.second; |
| bestCnt = move(res.first); |
| } |
| } |
| { |
| vector<double> d(n); |
| for (int i = 0; i < n; ++i) { |
| double w = (double)items[i].l / (double)CAP_L; |
| if (w == 0) w = 1e-18; |
| d[i] = (double)items[i].v / w; |
| } |
| auto res = greedy_by(d); |
| if (res.second > bestV) { |
| bestV = res.second; |
| bestCnt = move(res.first); |
| } |
| } |
|
|
| auto calcUsed = [&](const vector<long long>& cnt){ |
| long long um=0, ul=0, uv=0; |
| for (int i=0;i<n;++i){ |
| um += cnt[i]*items[i].m; |
| ul += cnt[i]*items[i].l; |
| uv += cnt[i]*items[i].v; |
| } |
| return tuple<long long,long long,long long>(um,ul,uv); |
| }; |
|
|
| |
| { |
| auto [usedM, usedL, usedV] = calcUsed(bestCnt); |
| |
| auto scoreDensity = [&](int i)->double{ |
| double wm = (double)items[i].m / (double)CAP_M; |
| double wl = (double)items[i].l / (double)CAP_L; |
| double w = wm + wl; |
| if (w == 0) w = 1e-18; |
| return (double)items[i].v / w; |
| }; |
| vector<int> order(n); |
| iota(order.begin(), order.end(), 0); |
| sort(order.begin(), order.end(), [&](int a,int b){ return scoreDensity(a) > scoreDensity(b); }); |
|
|
| bool improved = true; |
| int iter = 0; |
| while (improved && iter < 200) { |
| improved = false; |
| ++iter; |
| for (int j : order) { |
| if (bestCnt[j] >= items[j].q) continue; |
| long long nm = usedM + items[j].m; |
| long long nl = usedL + items[j].l; |
| if (nm <= CAP_M && nl <= CAP_L) { |
| bestCnt[j] += 1; |
| usedM = nm; usedL = nl; usedV += items[j].v; |
| improved = true; |
| continue; |
| } |
| long long needM = max(0LL, nm - CAP_M); |
| long long needL = max(0LL, nl - CAP_L); |
| if (needM<=0 && needL<=0) { |
| bestCnt[j] += 1; |
| usedM = nm; usedL = nl; usedV += items[j].v; |
| improved = true; |
| continue; |
| } |
| |
| struct Cand { int i; double eff; double costw; }; |
| vector<Cand> cands; |
| double alpha = 1.0 / max(1.0, (double)needM); |
| double beta = 1.0 / max(1.0, (double)needL); |
| for (int i = 0; i < n; ++i) { |
| if (bestCnt[i] <= 0) continue; |
| double cw = alpha * (double)items[i].m + beta * (double)items[i].l; |
| double eff = (cw <= 0 ? 1e18 : (double)items[i].v / cw); |
| cands.push_back({i, eff, cw}); |
| } |
| if (cands.empty()) continue; |
| sort(cands.begin(), cands.end(), [&](const Cand& A, const Cand& B){ |
| if (A.eff == B.eff) return A.i < B.i; |
| return A.eff < B.eff; |
| }); |
| long long rmM = 0, rmL = 0, lossV = 0; |
| vector<pair<int,long long>> toRemove; |
| long long needMm = needM, needLl = needL; |
| for (auto &c : cands) { |
| if (needMm <= 0 && needLl <= 0) break; |
| int i = c.i; |
| long long avail = bestCnt[i]; |
| if (avail <= 0) continue; |
| long long reqM = (needMm > 0 ? ( (needMm + items[i].m - 1) / items[i].m ) : 0); |
| long long reqL = (needLl > 0 ? ( (needLl + items[i].l - 1) / items[i].l ) : 0); |
| long long r = max(reqM, reqL); |
| if (r <= 0) continue; |
| if (r > avail) r = avail; |
| rmM += r * items[i].m; |
| rmL += r * items[i].l; |
| lossV += r * items[i].v; |
| needMm -= r * items[i].m; |
| needLl -= r * items[i].l; |
| toRemove.push_back({i, r}); |
| } |
| if (needMm <= 0 && needLl <= 0) { |
| if (items[j].v > lossV) { |
| |
| for (auto &p : toRemove) bestCnt[p.first] -= p.second; |
| bestCnt[j] += 1; |
| usedM = usedM - rmM + items[j].m; |
| usedL = usedL - rmL + items[j].l; |
| usedV = usedV - lossV + items[j].v; |
| improved = true; |
| } |
| } |
| } |
| } |
| bestV = usedV; |
| } |
|
|
| |
| cout << "{\n"; |
| for (int i = 0; i < n; ++i) { |
| cout << " \"" << items[i].name << "\": " << bestCnt[i]; |
| if (i + 1 < n) cout << ",\n"; |
| else cout << "\n"; |
| } |
| cout << "}\n"; |
| return 0; |
| } |