| #include <iostream> |
| #include <vector> |
| #include <string> |
| #include <algorithm> |
| #include <map> |
| #include <chrono> |
| #include <random> |
| #include <iomanip> |
|
|
| using namespace std; |
|
|
| |
| const long long MAX_MASS = 20000000; |
| const long long MAX_VOL = 25000000; |
|
|
| struct Item { |
| string name; |
| int id; |
| int q; |
| long long v; |
| long long m; |
| long long l; |
| }; |
|
|
| |
| vector<Item> items; |
| vector<string> keys_order; |
| map<string, int> name_to_id; |
| int N; |
|
|
| |
| vector<int> best_counts; |
| long long best_total_value = -1; |
|
|
| void parse_input() { |
| char c; |
| |
| |
| |
| while (cin >> c) { |
| if (c == '"') { |
| string key = ""; |
| |
| while (cin.get(c) && c != '"') { |
| key += c; |
| } |
| |
| |
| while (cin >> c && c != '['); |
| |
| |
| long long q, v, m, l; |
| |
| |
| cin >> q; |
| |
| while (cin >> c && c != ','); |
| |
| |
| cin >> v; |
| |
| while (cin >> c && c != ','); |
| |
| |
| cin >> m; |
| |
| while (cin >> c && c != ','); |
| |
| |
| cin >> l; |
| |
| while (cin >> c && c != ']'); |
| |
| Item item; |
| item.name = key; |
| item.q = (int)q; |
| item.v = v; |
| item.m = m; |
| item.l = l; |
| item.id = items.size(); |
| |
| name_to_id[key] = item.id; |
| keys_order.push_back(key); |
| items.push_back(item); |
| } |
| } |
| N = items.size(); |
| best_counts.resize(N, 0); |
| } |
|
|
| |
| auto start_time = chrono::high_resolution_clock::now(); |
|
|
| double get_elapsed() { |
| auto now = chrono::high_resolution_clock::now(); |
| return chrono::duration<double>(now - start_time).count(); |
| } |
|
|
| int main() { |
| |
| ios_base::sync_with_stdio(false); |
| cin.tie(NULL); |
| |
| parse_input(); |
| |
| if (N == 0) { |
| cout << "{}" << endl; |
| return 0; |
| } |
|
|
| |
| mt19937 rng(1337); |
| uniform_real_distribution<double> dist_real(0.0, 1.0); |
| uniform_int_distribution<int> dist_int(0, N - 1); |
|
|
| |
| vector<int> p(N); |
| for(int i=0; i<N; ++i) p[i] = i; |
|
|
| |
| vector<int> current_counts(N); |
| |
| |
| |
| |
| while (get_elapsed() < 0.90) { |
| |
| |
| |
| |
| double w_m = dist_real(rng); |
| double w_l = dist_real(rng); |
| |
| |
| double r = dist_real(rng); |
| if (r < 0.05) { w_m = 1.0; w_l = 0.0; } |
| else if (r < 0.10) { w_m = 0.0; w_l = 1.0; } |
| else if (r < 0.15) { w_m = 1.0; w_l = 1.0; } |
| else if (r < 0.20) { w_m = 1.0; w_l = 0.0001; } |
| else if (r < 0.25) { w_m = 0.0001; w_l = 1.0; } |
|
|
| |
| |
| |
| sort(p.begin(), p.end(), [&](int i, int j) { |
| double cost_i = w_m * ((double)items[i].m / MAX_MASS) + w_l * ((double)items[i].l / MAX_VOL); |
| double cost_j = w_m * ((double)items[j].m / MAX_MASS) + w_l * ((double)items[j].l / MAX_VOL); |
| if (cost_i < 1e-12) cost_i = 1e-12; |
| if (cost_j < 1e-12) cost_j = 1e-12; |
| return (items[i].v / cost_i) > (items[j].v / cost_j); |
| }); |
|
|
| |
| long long current_m = 0; |
| long long current_l = 0; |
| long long current_v = 0; |
| fill(current_counts.begin(), current_counts.end(), 0); |
|
|
| |
| |
| |
| bool forced = false; |
| int force_idx = -1; |
| |
| if (dist_real(rng) < 0.3) { |
| force_idx = dist_int(rng); |
| uniform_int_distribution<int> q_dist(1, items[force_idx].q); |
| int force_qty = q_dist(rng); |
| |
| |
| if (items[force_idx].m * (long long)force_qty <= MAX_MASS && |
| items[force_idx].l * (long long)force_qty <= MAX_VOL) { |
| current_counts[force_idx] = force_qty; |
| current_m += items[force_idx].m * force_qty; |
| current_l += items[force_idx].l * force_qty; |
| current_v += items[force_idx].v * force_qty; |
| forced = true; |
| } |
| } |
|
|
| |
| for (int i : p) { |
| if (forced && i == force_idx) continue; |
| |
| long long rem_m = MAX_MASS - current_m; |
| long long rem_l = MAX_VOL - current_l; |
| |
| if (rem_m < 0) rem_m = 0; |
| if (rem_l < 0) rem_l = 0; |
| |
| int can_take_m = (items[i].m == 0) ? items[i].q : (int)(rem_m / items[i].m); |
| int can_take_l = (items[i].l == 0) ? items[i].q : (int)(rem_l / items[i].l); |
| |
| int take = min(items[i].q, min(can_take_m, can_take_l)); |
| |
| |
| |
| if (take > 0 && dist_real(rng) < 0.05) { |
| take = max(0, take - 1); |
| } |
|
|
| current_counts[i] = take; |
| current_m += (long long)take * items[i].m; |
| current_l += (long long)take * items[i].l; |
| current_v += (long long)take * items[i].v; |
| } |
| |
| |
| |
| |
| |
| for (int i = 0; i < N; ++i) { |
| if (current_counts[i] < items[i].q) { |
| long long rem_m = MAX_MASS - current_m; |
| long long rem_l = MAX_VOL - current_l; |
| |
| if (items[i].m <= rem_m && items[i].l <= rem_l) { |
| int can_take_m = (items[i].m == 0) ? items[i].q : (int)(rem_m / items[i].m); |
| int can_take_l = (items[i].l == 0) ? items[i].q : (int)(rem_l / items[i].l); |
| int extra = min(items[i].q - current_counts[i], min(can_take_m, can_take_l)); |
| |
| current_counts[i] += extra; |
| current_m += (long long)extra * items[i].m; |
| current_l += (long long)extra * items[i].l; |
| current_v += (long long)extra * items[i].v; |
| } |
| } |
| } |
|
|
| |
| if (current_v > best_total_value) { |
| best_total_value = current_v; |
| best_counts = current_counts; |
| } |
| } |
|
|
| |
| cout << "{" << endl; |
| for (size_t i = 0; i < keys_order.size(); ++i) { |
| string key = keys_order[i]; |
| int id = name_to_id[key]; |
| cout << " \"" << key << "\": " << best_counts[id]; |
| if (i < keys_order.size() - 1) { |
| cout << ","; |
| } |
| cout << endl; |
| } |
| cout << "}" << endl; |
|
|
| return 0; |
| } |