64 lines
1.4 KiB
C++
64 lines
1.4 KiB
C++
|
#include <aocpp/Parsing.hpp>
|
||
|
#include <aocpp/Startup.hpp>
|
||
|
|
||
|
#include <boost/tuple/tuple.hpp>
|
||
|
#include <boost/spirit/include/qi.hpp>
|
||
|
|
||
|
#include <optional>
|
||
|
#include <stack>
|
||
|
|
||
|
namespace qi = boost::spirit::qi;
|
||
|
|
||
|
namespace {
|
||
|
|
||
|
auto
|
||
|
suffixed(std::uint64_t x, std::uint64_t y) -> std::optional<std::uint64_t>
|
||
|
{
|
||
|
while (x > 0) {
|
||
|
if (y == 0) { return x; }
|
||
|
if (x % 10 != y % 10) { return {}; }
|
||
|
x /= 10;
|
||
|
y /= 10;
|
||
|
}
|
||
|
return {};
|
||
|
}
|
||
|
|
||
|
auto
|
||
|
check(bool part2, std::uint64_t target, std::vector<std::uint64_t> const& numbers) -> bool
|
||
|
{
|
||
|
std::stack<boost::tuple<std::size_t, std::uint64_t>> work;
|
||
|
work.push({numbers.size() - 1, target});
|
||
|
|
||
|
while (!work.empty()){
|
||
|
auto [i, t] = work.top();
|
||
|
work.pop();
|
||
|
auto x = numbers[i];
|
||
|
if (i == 0) {
|
||
|
if (x == t) return true;
|
||
|
} else {
|
||
|
if (x < t) { work.push({i-1, t-x}); }
|
||
|
if (t % x == 0) { work.push({i-1, t/x}); }
|
||
|
if (part2) { if (auto u = suffixed(t,x)) { work.push({i-1, *u}); } }
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
} // namespace
|
||
|
|
||
|
auto Main(std::istream & in, std::ostream & out) -> void
|
||
|
{
|
||
|
std::vector<boost::tuple<std::uint64_t, std::vector<std::uint64_t>>> input;
|
||
|
aocpp::ParseSimple(in, *(qi::ulong_long >> ":" >> *(" " >> qi::ulong_long) >> "\n"), input);
|
||
|
|
||
|
std::uint64_t p1{}, p2{};
|
||
|
for (auto && [x, xs] : input) {
|
||
|
if (check(false, x, xs)) p1 += x;
|
||
|
if (check(true, x, xs)) p2 += x;
|
||
|
}
|
||
|
|
||
|
out << "Part 1: " << p1 << "\n"
|
||
|
<< "Part 2: " << p2 << "\n";
|
||
|
}
|