File size: 8,092 Bytes
14c9c2b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <map>
#include <chrono>
#include <random>
#include <iomanip>

using namespace std;

// Problem Constants
const long long MAX_MASS = 20000000; // 20 kg in mg
const long long MAX_VOL = 25000000;  // 25 L in uL

struct Item {
    string name;
    int id;
    int q;
    long long v;
    long long m;
    long long l;
};

// Global variables
vector<Item> items;
vector<string> keys_order;
map<string, int> name_to_id;
int N;

// Solution State
vector<int> best_counts;
long long best_total_value = -1;

void parse_input() {
    char c;
    // Skip initial whitespace and opening brace if present
    // The JSON input starts with {
    
    while (cin >> c) {
        if (c == '"') {
            string key = "";
            // Read key until closing quote
            while (cin.get(c) && c != '"') {
                key += c;
            }
            
            // Key found. Expect : then [
            while (cin >> c && c != '[');
            
            // Read array values
            long long q, v, m, l;
            
            // Read q
            cin >> q;
            // Skip to comma
            while (cin >> c && c != ',');
            
            // Read v
            cin >> v;
            // Skip to comma
            while (cin >> c && c != ',');
            
            // Read m
            cin >> m;
            // Skip to comma
            while (cin >> c && c != ',');
            
            // Read l
            cin >> l;
            // Skip to closing bracket
            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);
}

// Timer
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() {
    // Fast IO
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    
    parse_input();
    
    if (N == 0) {
        cout << "{}" << endl;
        return 0;
    }

    // Random number generator
    mt19937 rng(1337);
    uniform_real_distribution<double> dist_real(0.0, 1.0);
    uniform_int_distribution<int> dist_int(0, N - 1);

    // Indices for sorting
    vector<int> p(N);
    for(int i=0; i<N; ++i) p[i] = i;

    // Temporary solution storage
    vector<int> current_counts(N);
    
    // Main optimization loop
    // We run multiple iterations of randomized greedy heuristics
    // Since N=12, we can run many iterations in 1 second.
    while (get_elapsed() < 0.90) {
        
        // Strategy: Randomized Weights for Greedy
        // Generate random weights for mass and volume penalties
        // This corresponds to exploring the dual space of the relaxed LP.
        double w_m = dist_real(rng);
        double w_l = dist_real(rng);
        
        // Occasionally force extreme weights to explore boundaries
        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; } // Equal weight
        else if (r < 0.20) { w_m = 1.0; w_l = 0.0001; } // Nearly ignore volume
        else if (r < 0.25) { w_m = 0.0001; w_l = 1.0; } // Nearly ignore mass

        // Compute scores and sort
        // Heuristic: Value / Weighted_Cost
        // Cost is normalized by capacity to handle different units
        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);
        });

        // Current solution state
        long long current_m = 0;
        long long current_l = 0;
        long long current_v = 0;
        fill(current_counts.begin(), current_counts.end(), 0);

        // Perturbation Strategy:
        // Sometimes, force a random item to have a random count (Fix & Fill)
        // This helps escape local optima where greedy dominates.
        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);
            
            // Only apply if feasible alone
            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;
            }
        }

        // Greedy Fill Phase
        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));
            
            // Small mutation: Occasionally take slightly less than max possible
            // to leave space for other items
            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;
        }
        
        // Gap Filling Phase
        // Iterate through all items again to fill any remaining space
        // This is necessary because the sorted order might have skipped items 
        // that now fit in the small remaining space.
        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;
                 }
            }
        }

        // Update Global Best
        if (current_v > best_total_value) {
            best_total_value = current_v;
            best_counts = current_counts;
        }
    }

    // Output JSON
    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;
}