#include #include #include #include #include #include #include #include struct Classifier { void add_ranges(std::string const& s) { static const std::regex re("(.+): (\\d+)-(\\d+) or (\\d+)-(\\d+)"); std::smatch m; if (std::regex_search(s, m, re)) { auto field = field_names_.size(); field_names_.push_back(m.str(1)); std::cout << m.str(1) << "valid = "; add_range(m.str(2), m.str(3), field); std::cout << ", "; add_range(m.str(4), m.str(5), field); std::cout << "\n"; } } void add_range(std::string const& lows, std::string const& highs, std::size_t field) { int low = std::stoi(lows); int high = std::stoi(highs); ++high; unsigned flag = 1 << field; assert(flag != 0); if (num_to_valid_field_.size() < high) { num_to_valid_field_.resize(high, 0); } std::cout << "[" << low << ", " << high << "]"; while (low < high) { num_to_valid_field_[low] |= flag; ++low; } } void close() { idx_to_valid_field_.resize(0); idx_to_valid_field_.resize(field_names_.size(), (1 << field_names_.size()) - 1); } int count_errors(std::string const& s) const { std::string::size_type pos = 0; int result = 0; while (pos < s.size()) { std::size_t len = 0; int num = std::stoi(s.substr(pos), &len); if (num >= num_to_valid_field_.size() || num_to_valid_field_[num] == 0) { result += num == 0 ? 1 : num; std::cout << "Invalid: " << num << "\n"; } pos += len; while (pos < s.size() && s[pos] == ',') { ++pos; } } return result; } void mark_valid(std::string const& s) { std::string::size_type pos = 0; unsigned idx = 0; while (pos < s.size()) { std::size_t len = 0; int num = std::stoi(s.substr(pos), &len); unsigned valid_fields = num >= num_to_valid_field_.size() ? 0 : num_to_valid_field_[num]; idx_to_valid_field_[idx] &= valid_fields; pos += len; while (pos < s.size() && s[pos] == ',') { ++pos; } assert(idx_to_valid_field_[idx] != 0); ++idx; } } void print_valid() const { for (std::size_t idx = 0; idx < idx_to_valid_field_.size(); ++idx) { std::cout << "Index " << idx << " valid for fields:"; unsigned field = 0; for (auto valid_fields = idx_to_valid_field_[idx]; valid_fields != 0; valid_fields >>= 1) { if (valid_fields & 1) { std::cout << " " << field_names_[field]; } ++field; } std::cout << "\n"; } } void reduce() { bool changed = true; while (changed) { changed = false; for (unsigned idx = 0; idx < idx_to_valid_field_.size(); ++idx) { auto valid_fields = idx_to_valid_field_[idx]; if ((valid_fields & (valid_fields - 1)) == 0) { std::cout << "Index " << idx << " can only be field " << valid_fields << "\n"; for (unsigned idx2 = 0; idx2 < idx_to_valid_field_.size(); ++idx2) { if (idx == idx2) { continue; } changed |= (idx_to_valid_field_[idx2] & valid_fields) != 0; idx_to_valid_field_[idx2] &= ~valid_fields; } } } } } unsigned long calculate_product(std::string const& s, std::string const& prefix) { std::vector values; std::size_t pos = 0; while (pos < s.size()) { if (s[pos] == ',') { ++pos; } else { std::size_t len; values.push_back(std::stoi(s.substr(pos), &len)); pos += len; } } unsigned long product = 1; for (unsigned field = 0; field < field_names_.size(); ++field) { if (field_names_[field].substr(0, prefix.size()) == prefix) { unsigned idx = 0; while (idx < idx_to_valid_field_.size() && idx_to_valid_field_[idx] != (1 << field)) { ++idx; } assert(idx < idx_to_valid_field_.size()); product *= values[idx]; } } return product; } std::vector num_to_valid_field_; std::vector idx_to_valid_field_; std::vector field_names_; }; enum class State { Permitted, Your, Nearby }; int main(int argc, char** argv) { std::string line; State s = State::Permitted; Classifier c; int e = 0; std::string our_ticket; while (std::getline(std::cin, line)) { if (line == "your ticket:") { s = State::Your; } else if (line == "nearby tickets:") { s = State::Nearby; c.close(); } else if (line == "") { /* nothing */; } else if (s == State::Permitted) { c.add_ranges(line); } else if (s == State::Your) { our_ticket = line; } else if (s == State::Nearby) { auto e2 = c.count_errors(line); e += e2; if (e2 == 0) { c.mark_valid(line); } } } c.print_valid(); c.reduce(); c.print_valid(); std::cout << "Product: " << c.calculate_product(our_ticket, "departure ") << "\n"; return 0; }