Google Code Jam 2022 round1C Letter Blocks

Letter Blocks
Given N
strings, is it possible to construct a string(megatower) ? ( for any two elements have the same letter, all elements between them must also have that letter )

solution
Check a letter appearance
First, check all of the middle letters, which all letters other than the first and last consecutive segment of letters.
If a letter in middle letter appears more than one input string, it is impossible to construct the megatower.
String Types
Second, we group strings to two types.
- X
- XY
If S[i] is of the form X, all of the letters are same, insert to single[x]
If S[i] is of the form XY, start with character X and end with character Y, insert to start[X]
and end[Y]
.
start[X]
and end[Y]
must contain exactly 1 element for each letter X.
Algorithm
Finally, we can create megatower as following algorithms.
- Pick an arbitrary string from the candidate’s set and start the block with it.
- Let e = last letter of the current solution. If starts[e] != null, add starts[e] to current solution and repeat step 2. Otherwise goto step 1.
- If candidate’s set is empty, print solution. Otherwise, print
IMPOSSIBLE
.
If there is a unused string, it is impossible to create megatower.
#include <bits/stdc++.h> using namespace std; using ll = long long; namespace std { template <class Fun> class y_combinator_result { Fun fun_; public: template <class T> explicit y_combinator_result(T &&fun) : fun_(std::forward<T>(fun)) {} template <class... Args> decltype(auto) operator()(Args &&...args) { return fun_(std::ref(*this), std::forward<Args>(args)...); } }; template <class Fun> decltype(auto) y_combinator(Fun &&fun) { return y_combinator_result<std::decay_t<Fun>>(std::forward<Fun>(fun)); } } // namespace std void solve() { int n; cin >> n; vector<string> a(n); vector<vector<int>> single(26); vector<vector<int>> start(26); vector<vector<int>> end(26); vector<int> ans; map<char, int> m; // Check all of the middle letters for (int i = 0; i < n; ++i) { cin >> a[i]; for (int j = 1; j < a[i].size(); ++j) { if (a[i][j - 1] != a[i][j]) { m[a[i][j]]++; } } for (int j = a[i].size() - 2; j >= 0; --j) { if (a[i][j] != a[i][j + 1]) { m[a[i][a[i].size() - 1]]--; break; } } } for (auto x : m) { if (x.second >= 2) { cout << "IMPOSSIBLE"; return; } } for (int i = 0; i < n; ++i) { if (m[a[i][0]] != 0 || m[a[i][a[i].size() - 1]] != 0) { cout << "IMPOSSIBLE"; return; } } // start[x]: start with letter x // end[x]: end with letter x // single[x]: all letters are x for (int i = 0; i < n; ++i) { char t = a[i][0]; char tt = a[i][a[i].size() - 1]; bool flag = false; for (int j = 0; j < a[i].size(); ++j) { if (a[i][j] != t) flag = true; } if (flag == false) single[t - 'A'].push_back(i); else { start[t - 'A'].push_back(i); end[tt - 'A'].push_back(i); } } for (int i = 0; i < 26; ++i) { if (start[i].size() >= 2 || end[i].size() >= 2) { cout << "IMPOSSIBLE"; return; } } map<int, int> used; for (int i = 0; i < 26; ++i) { if (!used[i] && end[i].size() == 0) { y_combinator( [&](auto self, int pos) -> void { used[pos] = true; if (single[pos].size() != 0) { for (auto x : single[pos]) ans.push_back(x); } if (start[pos].size() != 0) { int t = start[pos][0]; ans.push_back(t); self(a[t][a[t].size() - 1] - 'A'); } })(i); } } if (ans.size() != n) { cout << "IMPOSSIBLE"; } else { for (auto x : ans) { cout << a[x]; } } } int main() { cin.tie(0); ios_base::sync_with_stdio(false); int t; cin >> t; for (int tt = 1; tt <= t; ++tt) { cout << "Case #" << tt << ": "; solve(); cout << endl; } return 0; }