File size: 5,837 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
#include <iostream>
#include <vector>
#include <string>
#include <array>
#include <unordered_map>
#include <algorithm>
#include <utility>
#include "json.hpp"

using json = nlohmann::json;

const long long MAX_MASS = 20000000;
const long long MAX_VOLUME = 25000000;
const int NUM_ITEMS = 12;
const int HALF_NUM_ITEMS = 6;

struct Item {
    std::string name;
    int q;
    long long v, m, l;
    int original_idx;
};

struct State {
    long long m, l, v;
    std::array<int, HALF_NUM_ITEMS> counts;
};

struct pair_hash {
    template <class T1, class T2>
    std::size_t operator () (const std::pair<T1, T2>& p) const {
        auto h1 = std::hash<T1>{}(p.first);
        auto h2 = std::hash<T2>{}(p.second);
        // A simple way to combine hashes, found to be effective in practice.
        return h1 ^ (h2 << 1);
    }
};

using StatesMap = std::unordered_map<std::pair<long long, long long>, std::pair<long long, std::array<int, HALF_NUM_ITEMS>>, pair_hash>;

StatesMap generate_states(const std::vector<Item>& items) {
    StatesMap states;
    states.reserve(100000); // Pre-allocation to reduce rehashes
    states[{0, 0}] = {0, {}};

    for (int i = 0; i < items.size(); ++i) {
        const auto& item = items[i];
        long long current_q = item.q;
        
        std::vector<long long> meta_quantities;
        for (long long p = 1; current_q > 0; p *= 2) {
            long long take = std::min(p, current_q);
            meta_quantities.push_back(take);
            current_q -= take;
        }

        for (const auto& k : meta_quantities) {
            long long delta_m = k * item.m;
            long long delta_l = k * item.l;
            long long delta_v = k * item.v;

            std::vector<std::pair<std::pair<long long, long long>, std::pair<long long, std::array<int, HALF_NUM_ITEMS>>>> updates;
            updates.reserve(states.size());

            for (const auto& s : states) {
                long long new_m = s.first.first + delta_m;
                long long new_l = s.first.second + delta_l;

                if (new_m <= MAX_MASS && new_l <= MAX_VOLUME) {
                    long long new_v = s.second.first + delta_v;
                    auto new_counts = s.second.second;
                    new_counts[i] += k;
                    updates.push_back({{new_m, new_l}, {new_v, new_counts}});
                }
            }
            
            for (const auto& update : updates) {
                const auto& key = update.first;
                const auto& val = update.second;
                auto it = states.find(key);
                if (it == states.end() || it->second.first < val.first) {
                    states[key] = val;
                }
            }
        }
    }
    return states;
}

std::vector<State> prune_and_convert(const StatesMap& states_map) {
    std::vector<State> states_vec;
    states_vec.reserve(states_map.size());
    for (const auto& pair : states_map) {
        states_vec.push_back({pair.first.first, pair.first.second, pair.second.first, pair.second.second});
    }

    std::sort(states_vec.begin(), states_vec.end(), [](const State& a, const State& b) {
        if (a.m != b.m) return a.m < b.m;
        if (a.l != b.l) return a.l < b.l;
        return a.v > b.v;
    });

    std::vector<State> pruned;
    pruned.reserve(states_vec.size());
    for (const auto& s : states_vec) {
        while (!pruned.empty() && pruned.back().l >= s.l && pruned.back().v <= s.v) {
            pruned.pop_back();
        }
        if (pruned.empty() || pruned.back().l < s.l || pruned.back().v < s.v) {
            pruned.push_back(s);
        }
    }
    return pruned;
}

int main() {
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(NULL);

    json input_json;
    std::cin >> input_json;

    std::vector<Item> all_items;
    int idx = 0;
    for (auto& [key, value] : input_json.items()) {
        all_items.push_back({key, value[0], value[1], value[2], value[3], idx++});
    }
    
    std::sort(all_items.begin(), all_items.end(), [](const Item& a, const Item& b){
        return a.name < b.name;
    });

    std::vector<Item> groupA(all_items.begin(), all_items.begin() + HALF_NUM_ITEMS);
    std::vector<Item> groupB(all_items.begin() + HALF_NUM_ITEMS, all_items.end());

    StatesMap states_map_A = generate_states(groupA);
    StatesMap states_map_B = generate_states(groupB);
    
    std::vector<State> listA = prune_and_convert(states_map_A);
    std::vector<State> listB = prune_and_convert(states_map_B);
    
    std::sort(listA.begin(), listA.end(), [](const State& a, const State& b) {
        return a.m < b.m;
    });
    std::sort(listB.begin(), listB.end(), [](const State& a, const State& b) {
        return a.m < b.m;
    });

    long long max_val = 0;
    std::array<int, NUM_ITEMS> best_counts = {};

    int ptrB = listB.size() - 1;
    for (const auto& s_a : listA) {
        while (ptrB >= 0 && s_a.m + listB[ptrB].m > MAX_MASS) {
            ptrB--;
        }
        if (ptrB < 0) {
            break;
        }

        for (int i = 0; i <= ptrB; ++i) {
            const auto& s_b = listB[i];
            if (s_a.l + s_b.l <= MAX_VOLUME) {
                if (s_a.v + s_b.v > max_val) {
                    max_val = s_a.v + s_b.v;
                    for (int j = 0; j < HALF_NUM_ITEMS; ++j) {
                        best_counts[groupA[j].original_idx] = s_a.counts[j];
                    }
                    for (int j = 0; j < HALF_NUM_ITEMS; ++j) {
                        best_counts[groupB[j].original_idx] = s_b.counts[j];
                    }
                }
            }
        }
    }

    json output_json;
    for(int i = 0; i < NUM_ITEMS; ++i) {
        output_json[all_items[i].name] = best_counts[i];
    }
    std::cout << output_json.dump(1, '\t') << std::endl;

    return 0;
}