Amedeo
SYMBIOSYS OF
PURPOSE & STYLE
Follow us

Search

ekusiadadus
  -  Programming   -  Competitive Programming   -  Google   -  CodeJam   -  Google Code Jam 2022 round1C Letter Blocks
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 )

Towers of ABCCC, AAA, and ACBCC.
Letter Blocks

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.

  1. X
  2. 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.

  1. Pick an arbitrary string from the candidate’s set and start the block with it.
  2. 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.
  3. 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;
}
Leave a Comment