#include #include #include #include #include #include #include #include #include #include namespace qi = boost::spirit::qi; namespace { auto try_subtract(std::uint64_t t, std::uint64_t x) -> std::optional { return x < t ? std::optional{t - x} : std::nullopt; } auto try_divide(std::uint64_t t, std::uint64_t x) -> std::optional { return t % x == 0 ? std::optional{t / x} : std::nullopt; } auto try_unsuffix(std::uint64_t x, std::uint64_t y) -> std::optional { while (x > 0) { if (y == 0) { return x; } if (x % 10 != y % 10) return std::nullopt; x /= 10; y /= 10; } return std::nullopt; } auto calibrated( std::uint64_t const target, std::vector const& numbers, auto... ops ) -> bool { if (numbers.empty()) { return false; } auto work = std::stack>{}; work.emplace(numbers.size() - 1, target); while (not work.empty()) { auto const [i, t] = work.top(); work.pop(); auto const x = numbers[i]; if (i == 0) { if (x == t) { return true; } } else { ([&](auto const op) { if (auto const u = op(t, x)) { work.emplace(i - 1, *u); } }(ops), ...); } } return false; } } // namespace auto Main(std::istream & in, std::ostream & out) -> void { auto const input = aocpp::ParseSimple >>> (in, *(qi::ulong_long >> ':' >> +(' ' >> qi::ulong_long) >> '\n')); std::uint64_t p1 = 0, p2 = 0; for (auto && [x, xs] : input) { if (calibrated(x, xs, try_subtract, try_divide)) p1 += x; if (calibrated(x, xs, try_subtract, try_divide, try_unsuffix)) p2 += x; } out << "Part 1: " << p1 << "\n" << "Part 2: " << p2 << "\n"; }