#include #include #include #include #include #include #include #include #include using UInt = std::uint64_t; using StringVec = std::vector; using UIntVec = std::vector; using Pos = std::pair; using PosVec = std::vector; auto split(std::string_view line) -> std::pair { auto pos = line.find(' '); auto pattern = line.substr(0, pos); UIntVec nums; line = line.substr(pos); while (!line.empty()) { line = line.substr(1); char* n{nullptr}; nums.emplace_back(std::strtoll(line.data(), &n, 10)); line = line.substr(n - line.data()); } return std::make_pair(pattern, nums); } std::unordered_map counts; auto valid_sequences(std::string_view pattern, UIntVec::const_iterator begin, UIntVec::const_iterator end) -> UInt; auto generate_pattern(std::string pattern, UIntVec::const_iterator begin, UIntVec::const_iterator end) -> UInt { while (begin != end) { if (pattern.empty()) { // We still have ###s to add but nowhere to put them - this isn't a match. return 0; } if (pattern[0] == '?') { // We don't know what the first character is so let's try both options recursively. auto new_pattern{pattern}; new_pattern[0] = '.'; auto count = valid_sequences(new_pattern, begin, end); new_pattern[0] = '#'; count += valid_sequences(new_pattern, begin, end); return count; } if (pattern[0] == '.') { // If the pattern begins with a '.' then we just skip over it. pattern = pattern.substr(1); continue; } /* We must have a '#' now. */ assert(pattern[0] == '#'); if (pattern.size() < *begin) { // Not enough space. return 0; } for (std::size_t count = 0; count < *begin; ++count) { // Check for dots. if (pattern[count] == '.') { return 0; } } // Move along the pattern. pattern = pattern.substr(*begin++); if (begin != end) { if (pattern.empty()) { return 0; } if (pattern[0] == '#') { return 0; } pattern = pattern.substr(1); } } return pattern.find('#') == std::string_view::npos; } auto valid_sequences(std::string_view pattern, UIntVec::const_iterator begin, UIntVec::const_iterator end) -> UInt { std::string hash = std::string(pattern); for (auto it{begin}; it != end; ++it) { hash += ','; hash += std::to_string(*it); } auto it = counts.find(hash); if (it == counts.end()) { bool success; std::tie(it, success) = counts.insert( {hash, generate_pattern(std::string(pattern), begin, end)}); } return it->second; } auto main() -> int try { std::string line; UInt count{0}; while (std::getline(std::cin, line)) { auto [pattern, nums] = split(line); UInt line_count{0}; std::string unfolded_pattern{pattern}; UIntVec unfolded_nums{nums.begin(), nums.end()}; for (unsigned i = 1; i < 5; ++i) { unfolded_pattern += '?'; unfolded_pattern += pattern; unfolded_nums.insert(unfolded_nums.begin(), nums.begin(), nums.end()); } line_count += valid_sequences(unfolded_pattern, unfolded_nums.begin(), unfolded_nums.end()); std::cout << line << ": " << line_count << '\n'; count += line_count; } std::cout << "Valid sequences: " << count << '\n'; return EXIT_SUCCESS;; } catch (...) { std::cerr << "Uncaught exception.\n"; return EXIT_FAILURE; }