Problem p00896 (C++) — buggy submission, verdict: Time Limit Exceeded

// Name: Weaker then Planned
// Level:
// Category:
// Note:

#include <algorithm>
#include <array>
#include <cstdio>
#include <iostream>
#include <map>
#include <set>
#include <string>
#include <vector>

using namespace std;

#define TIMES(i, n) for (int i = 0; i < (n); ++i)

typedef array<char, 256> Table;
Table table, ans;
bool found = false;

bool check(const vector<string> &words, const vector<string> &crypted) {
  for (const string &cs : crypted) {
    for (const string &w : words) {
      if (cs.size() != w.size())
        continue;
      bool ok = true;
      TIMES(i, cs.size()) {
        const char cch = cs[i];
        const char wch = w[i];
        if (table[cch] != 0 && table[cch] != wch) {
          ok = false;
          break;
        }
      }
      if (ok)
        goto next_cs;
    }
    // cout << "no match for " << cs << endl;
    return false;
  next_cs:;
  }
  return true;
}

bool search(int pos, const vector<string> &words,
            const vector<string> &crypted) {
  if (pos == crypted.size()) {
    if (found)
      throw "ambiguous";
    found = true;
    ans = table;
    return true;
  }

  const string &cs = crypted[pos];
  for (const string &w : words) {
    if (w.size() != cs.size())
      continue;
    Table bak = table;
    TIMES(i, w.size()) {
      const char cch = cs[i];
      const char wch = w[i];
      // Check whether consistency
      if (table[cch] != 0 && table[cch] != wch) {
        goto next;
      }
      if (table[wch] != 0 && table[wch] != cch) {
        goto next;
      }
      table[cch] = wch;
      table[wch] = cch;
    }
    // cout << cs << ' ' << w << endl;
    //  Check consistency for other words
    if (!check(words, crypted))
      goto next;
    search(pos + 1, words, crypted);
  next:
    table = bak;
  }
  return false;
}

bool solve() {
  int N;
  cin >> N;
  if (!N)
    return false;

  vector<string> words(N);
  TIMES(i, N) { cin >> words[i]; }
  vector<string> seq;
  while (true) {
    string w;
    cin >> w;
    if (w[w.size() - 1] == '.') {
      seq.push_back(w.substr(0, w.size() - 1));
      break;
    } else {
      seq.push_back(w);
    }
  }
  vector<pair<int, string>> v;
  TIMES(i, seq.size()) {
    const auto &s = seq[i];
    vector<bool> seen(26, false);
    int cnt = 0;
    for (char c : s) {
      if (seen[c - 'A'])
        continue;
      seen[c - 'A'] = true;
      ++cnt;
    }
    v.push_back(make_pair(i, s));
  }
  sort(v.begin(), v.end());
  v.erase(unique(v.begin(), v.end()), v.end());
  reverse(v.begin(), v.end());

  vector<string> crypted;
  for (const auto &p : v) {
    crypted.push_back(p.second);
  }
  fill(table.begin(), table.end(), 0);
  found = false;
  try {
    search(0, words, crypted);
  } catch (const char *s) {
    found = false;
  }
  if (found) {
    bool first = true;
    for (const string &s : seq) {
      if (!first)
        cout << ' ';
      for (char c : s) {
        cout << ans[c];
      }
      first = false;
    }
    cout << '.' << endl;
  } else {
    cout << "-." << endl;
  }
  return true;
}

int main() {
  cin.tie(0);
  ios::sync_with_stdio(0);

  while (solve())
    ;
  return 0;
}

Error: TLE

Fixed submission:

// Name: Weaker then Planned
// Level:
// Category:
// Note:

#include <algorithm>
#include <array>
#include <cstdio>
#include <iostream>
#include <map>
#include <set>
#include <string>
#include <vector>

using namespace std;

#define TIMES(i, n) for (int i = 0; i < (n); ++i)

inline int popcount(unsigned x) {
  x = (x & 0x55555555U) + ((x & 0xaaaaaaaaU) >> 1);
  x = (x & 0x33333333U) + ((x & 0xccccccccU) >> 2);
  x = (x & 0x0f0f0f0fU) + ((x & 0xf0f0f0f0U) >> 4);
  x = (x & 0x00ff00ffU) + ((x & 0xff00ff00U) >> 8);
  x = (x & 0x0000ffffU) + ((x & 0xffff0000U) >> 16);
  return x;
}

array<char, 256> table, ans;
bool found = false;

bool check(const vector<pair<string, int>> &words,
           const set<pair<string, int>> &crypted) {
  for (const auto &w : crypted) {
    string s = w.first;
    for (char &c : s) {
      c = table[c];
    }
    if (find_if(words.begin(), words.end(), [&s](const pair<string, int> &ww) {
          return ww.first == s;
        }) == words.end())
      return false;
  }
  return true;
}

bool search(const vector<pair<string, int>> &words,
            const set<pair<string, int>> &crypted, int known_pat) {
  string w = "";
  int max_unknown = 0;
  int mask = 0;
  for (const auto &s : crypted) {
    int unknown = popcount(s.second & ~known_pat);
    if (unknown > max_unknown) {
      w = s.first;
      max_unknown = unknown;
      mask = s.second & ~known_pat;
    }
  }
  if (max_unknown == 0) {
    if (!check(words, crypted))
      return false;
    if (found)
      throw "ambiguous";
    found = true;
    ans = table;
    return true;
  }
  for (const auto &word : words) {
    // cout << known_pat << ' ' << w << ' ' << word << endl;
    if (word.first.size() != w.size())
      continue;
    TIMES(i, word.first.size()) {
      const char cch = w[i];
      const char wch = word.first[i];
      if (table[cch] != 0 && table[cch] != wch) {
        // cout << cch << ' ' << table[cch] << endl;
        goto next;
      }
      if (table[wch] != 0 && table[wch] != cch) {
        goto next;
      }
      table[cch] = wch;
      table[wch] = cch;
    }
    // cout << "ok" << endl;
    search(words, crypted, known_pat | mask | word.second);
  next:
    TIMES(i, word.first.size()) {
      const char cch = w[i];
      const char wch = word.first[i];
      if (mask & (1 << (cch - 'A'))) {
        // cout << known_pat << " clear " << cch << endl;
        table[cch] = table[wch] = 0;
      }
    }
  }
  return false;
}

bool solve() {
  int N;
  cin >> N;
  if (!N)
    return false;

  vector<pair<string, int>> words(N);
  TIMES(i, N) {
    string str;
    cin >> str;
    int mask = 0;
    for (char c : str) {
      mask |= 1 << (c - 'A');
    }
    words[i] = make_pair(str, mask);
  }
  vector<string> seq;
  while (true) {
    string w;
    cin >> w;
    if (w[w.size() - 1] == '.') {
      seq.push_back(w.substr(0, w.size() - 1));
      break;
    } else {
      seq.push_back(w);
    }
  }

  set<pair<string, int>> crypted;
  for (const string &s : seq) {
    int mask = 0;
    for (char c : s) {
      mask |= (1 << (c - 'A'));
    }
    crypted.insert(make_pair(s, mask));
  }

  fill(table.begin(), table.end(), 0);
  found = false;
  try {
    search(words, crypted, 0);
  } catch (const char *s) {
    found = false;
  }
  if (found) {
    bool first = true;
    for (const string &s : seq) {
      if (!first)
        cout << ' ';
      for (char c : s) {
        cout << ans[c];
      }
      first = false;
    }
    cout << '.' << endl;
  } else {
    cout << "-." << endl;
  }
  return true;
}

int main() {
  cin.tie(0);
  ios::sync_with_stdio(0);

  while (solve())
    ;
  return 0;
}