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

#include <algorithm>
#include <bitset>
#include <iostream>
#include <string>
#include <unordered_set>
#include <vector>

using namespace std;
typedef unsigned int ull;
static const ull HASH_BASE = 1000000007ull;
static const char CHARACTERS[] = ".ABCDEFGHIJKLMNOPQRSTUVWXYZ";

bool is_covered(const string &t, int m, const vector<bitset<65536> *> &pieces) {
  const int n = t.size();
  if (m > n) {
    return false;
  }
  ull hash_remove = 1ull, h = 0ull;
  for (int i = 0; i < m; ++i) {
    hash_remove *= HASH_BASE;
    h = (h * HASH_BASE) + t[i];
  }
  int tail = 0;
  for (int i = m; i <= n; ++i) {
    if (pieces[h >> 16] != nullptr && (*pieces[h >> 16])[h & 0xffff]) {
      tail = i;
    }
    // if(pieces.find(h) != pieces.end()){ tail = i; }
    if (tail == i - m) {
      return false;
    }
    h = (h * HASH_BASE) + t[i];
    h -= (hash_remove * t[i - m]);
  }
  return tail == n;
}

int main() {
  ios_base::sync_with_stdio(false);
  while (true) {
    int d, n;
    cin >> d >> n;
    if (d == 0 && n == 0) {
      break;
    }
    string s;
    cin >> s;
    vector<string> pieces(n);
    for (int i = 0; i < n; ++i) {
      cin >> pieces[i];
    }
    const int m = pieces[0].size();
    // unordered_set<ull> hashes(n);
    vector<bitset<65536> *> hashes(65536, nullptr);
    for (int i = 0; i < n; ++i) {
      ull hash = 0;
      for (int j = 0; j < m; ++j) {
        hash = (hash * HASH_BASE) + pieces[i][j];
      }
      // hashes.insert(hash);
      if (hashes[hash >> 16] == nullptr) {
        hashes[hash >> 16] = new bitset<65536>();
      }
      hashes[hash >> 16]->set(hash & 0xffff);
    }
    n = s.size();
    ull hash_remove = 1;
    for (int i = 0; i < m; ++i) {
      hash_remove *= HASH_BASE;
    }
    vector<string> solutions;
    if (is_covered(s, m, hashes)) {
      solutions.push_back(s);
    }
    if (d >= 1) {
      // insert
      for (int i = 0; i <= n; ++i) {
        string t(n + 1, ' ');
        for (int j = 0; j < n; ++j) {
          t[j >= i ? j + 1 : j] = s[j];
        }
        for (int x = 0; x < 27; ++x) {
          t[i] = CHARACTERS[x];
          if (is_covered(t, m, hashes)) {
            solutions.push_back(t);
          }
        }
      }
      // replace
      for (int i = 0; i < n; ++i) {
        string t(s);
        for (int x = 0; x < 27; ++x) {
          t[i] = CHARACTERS[x];
          if (is_covered(t, m, hashes)) {
            solutions.push_back(t);
          }
        }
      }
      // remove
      for (int i = 0; i < n; ++i) {
        string t(n - 1, ' ');
        for (int j = 0, k = 0; j < n; ++j) {
          if (i == j) {
            continue;
          }
          t[k++] = s[j];
        }
        if (is_covered(t, m, hashes)) {
          solutions.push_back(t);
        }
      }
    }
    if (d >= 2) {
      // insert
      for (int i = 0; i <= n; ++i) {
        string t1(n + 1, ' ');
        for (int j = 0; j < n; ++j) {
          t1[j >= i ? j + 1 : j] = s[j];
        }
        // insert-insert
        for (int j = 0; j <= n + 1; ++j) {
          string t2(n + 2, ' ');
          for (int k = 0; k <= n; ++k) {
            t2[k >= j ? k + 1 : k] = t1[k];
          }
          for (int a = 0; a < 27; ++a) {
            t2[i] = CHARACTERS[a];
            for (int b = 0; b < 27; ++b) {
              t2[j] = CHARACTERS[b];
              if (is_covered(t2, m, hashes)) {
                solutions.push_back(t2);
              }
            }
          }
        }
        // insert-replace
        for (int j = 0; j <= n; ++j) {
          if (i == j) {
            continue;
          }
          string t2(t1);
          for (int a = 0; a < 27; ++a) {
            t2[i] = CHARACTERS[a];
            for (int b = 0; b < 27; ++b) {
              t2[j] = CHARACTERS[b];
              if (is_covered(t2, m, hashes)) {
                solutions.push_back(t2);
              }
            }
          }
        }
        // insert-remove
        for (int j = 0; j <= n; ++j) {
          if (i == j) {
            continue;
          }
          string t2(n, ' ');
          for (int k = 0, p = 0; k <= n; ++k) {
            if (k == j) {
              continue;
            }
            t2[p++] = t1[k];
          }
          const int p = (i >= j ? i - 1 : i);
          for (int a = 0; a < 27; ++a) {
            t2[p] = CHARACTERS[a];
            if (is_covered(t2, m, hashes)) {
              solutions.push_back(t2);
            }
          }
        }
      }
      // replace
      for (int i = 0; i < n; ++i) {
        // replace-replace
        for (int j = i + 1; j < n; ++j) {
          string t(s);
          for (int a = 0; a < 27; ++a) {
            t[i] = CHARACTERS[a];
            for (int b = 0; b < 27; ++b) {
              t[j] = CHARACTERS[b];
              if (is_covered(t, m, hashes)) {
                solutions.push_back(t);
              }
            }
          }
        }
        // replace-remove
        for (int j = 0; j < n; ++j) {
          if (i == j) {
            continue;
          }
          string t(n - 1, ' ');
          for (int k = 0, p = 0; k < n; ++k) {
            if (k == j) {
              continue;
            }
            t[p++] = s[k];
          }
          const int p = (i >= j ? i - 1 : i);
          for (int a = 0; a < 27; ++a) {
            t[p] = CHARACTERS[a];
            if (is_covered(t, m, hashes)) {
              solutions.push_back(t);
            }
          }
        }
      }
      // remove-remove
      string t(n - 2, ' ');
      for (int i = 0; i < n; ++i) {
        for (int j = i + 1; j < n; ++j) {
          for (int k = 0, p = 0; k < n; ++k) {
            if (k == i || k == j) {
              continue;
            }
            t[p++] = s[k];
          }
          if (is_covered(t, m, hashes)) {
            solutions.push_back(t);
          }
        }
      }
    }
    sort(solutions.begin(), solutions.end());
    solutions.erase(unique(solutions.begin(), solutions.end()),
                    solutions.end());
    cout << solutions.size() << endl;
    if (solutions.size() <= 5) {
      for (const auto &sol : solutions) {
        cout << sol << endl;
      }
    }
    for (auto ptr : hashes) {
      delete ptr;
    }
  }
  return 0;
}

Error: TLE

Fixed submission:

#include <algorithm>
#include <bitset>
#include <iostream>
#include <string>
#include <unordered_set>
#include <vector>

using namespace std;
typedef unsigned int ull;
static const ull HASH_BASE = 1000000007ull;
static const char CHARACTERS[] = ".ABCDEFGHIJKLMNOPQRSTUVWXYZ";

bool is_covered(const string &t, int m, const unordered_set<ull> &pieces) {
  const int n = t.size();
  if (m > n) {
    return false;
  }
  ull hash_remove = 1ull, h = 0ull;
  for (int i = 0; i < m; ++i) {
    hash_remove *= HASH_BASE;
    h = (h * HASH_BASE) + t[i];
  }
  int tail = 0;
  for (int i = m; i <= n; ++i) {
    if (pieces.find(h) != pieces.end()) {
      tail = i;
    }
    if (tail == i - m) {
      return false;
    }
    h = (h * HASH_BASE) + t[i];
    h -= (hash_remove * t[i - m]);
  }
  return tail == n;
}

int main() {
  ios_base::sync_with_stdio(false);
  while (true) {
    int d, n;
    cin >> d >> n;
    if (d == 0 && n == 0) {
      break;
    }
    string s;
    cin >> s;
    vector<string> pieces(n);
    for (int i = 0; i < n; ++i) {
      cin >> pieces[i];
    }
    const int m = pieces[0].size();
    unordered_set<ull> hashes(n);
    for (int i = 0; i < n; ++i) {
      ull hash = 0;
      for (int j = 0; j < m; ++j) {
        hash = (hash * HASH_BASE) + pieces[i][j];
      }
      hashes.insert(hash);
    }
    n = s.size();
    ull hash_remove = 1;
    for (int i = 0; i < m; ++i) {
      hash_remove *= HASH_BASE;
    }
    vector<string> solutions;
    if (is_covered(s, m, hashes)) {
      solutions.push_back(s);
    }
    if (d >= 1) {
      // insert
      for (int i = 0; i <= n; ++i) {
        string t(n + 1, ' ');
        for (int j = 0; j < n; ++j) {
          t[j >= i ? j + 1 : j] = s[j];
        }
        for (int x = 0; x < 27; ++x) {
          t[i] = CHARACTERS[x];
          if (is_covered(t, m, hashes)) {
            solutions.push_back(t);
          }
        }
      }
      // replace
      for (int i = 0; i < n; ++i) {
        string t(s);
        for (int x = 0; x < 27; ++x) {
          t[i] = CHARACTERS[x];
          if (is_covered(t, m, hashes)) {
            solutions.push_back(t);
          }
        }
      }
      // remove
      for (int i = 0; i < n; ++i) {
        string t(n - 1, ' ');
        for (int j = 0, k = 0; j < n; ++j) {
          if (i == j) {
            continue;
          }
          t[k++] = s[j];
        }
        if (is_covered(t, m, hashes)) {
          solutions.push_back(t);
        }
      }
    }
    if (d >= 2) {
      // insert
      for (int i = 0; i <= n; ++i) {
        string t1(n + 1, ' ');
        for (int j = 0; j < n; ++j) {
          t1[j >= i ? j + 1 : j] = s[j];
        }
        // insert-insert
        for (int j = 0; j <= n + 1; ++j) {
          string t2(n + 2, ' ');
          for (int k = 0; k <= n; ++k) {
            t2[k >= j ? k + 1 : k] = t1[k];
          }
          for (int a = 0; a < 27; ++a) {
            t2[i] = CHARACTERS[a];
            for (int b = 0; b < 27; ++b) {
              t2[j] = CHARACTERS[b];
              if (is_covered(t2, m, hashes)) {
                solutions.push_back(t2);
              }
            }
          }
        }
        // insert-replace
        for (int j = 0; j <= n; ++j) {
          if (i == j) {
            continue;
          }
          string t2(t1);
          for (int a = 0; a < 27; ++a) {
            t2[i] = CHARACTERS[a];
            for (int b = 0; b < 27; ++b) {
              t2[j] = CHARACTERS[b];
              if (is_covered(t2, m, hashes)) {
                solutions.push_back(t2);
              }
            }
          }
        }
        // insert-remove
        for (int j = 0; j <= n; ++j) {
          if (i == j) {
            continue;
          }
          string t2(n, ' ');
          for (int k = 0, p = 0; k <= n; ++k) {
            if (k == j) {
              continue;
            }
            t2[p++] = t1[k];
          }
          for (int a = 0; a < 27; ++a) {
            t2[i] = CHARACTERS[a];
            if (is_covered(t2, m, hashes)) {
              solutions.push_back(t2);
            }
          }
        }
      }
      // replace
      for (int i = 0; i < n; ++i) {
        // replace-replace
        for (int j = i + 1; j < n; ++j) {
          string t(s);
          for (int a = 0; a < 27; ++a) {
            t[i] = CHARACTERS[a];
            for (int b = 0; b < 27; ++b) {
              t[j] = CHARACTERS[b];
              if (is_covered(t, m, hashes)) {
                solutions.push_back(t);
              }
            }
          }
        }
        // replace-remove
        for (int j = 0; j < n; ++j) {
          if (i == j) {
            continue;
          }
          string t(n - 1, ' ');
          for (int k = 0, p = 0; k < n; ++k) {
            if (k == j) {
              continue;
            }
            t[p++] = s[k];
          }
          for (int a = 0; a < 27; ++a) {
            t[i] = CHARACTERS[a];
            if (is_covered(t, m, hashes)) {
              solutions.push_back(t);
            }
          }
        }
      }
      // remove-remove
      string t(n - 2, ' ');
      for (int i = 0; i < n; ++i) {
        for (int j = i + 1; j < n; ++j) {
          for (int k = 0, p = 0; k < n; ++k) {
            if (k == i || k == j) {
              continue;
            }
            t[p++] = s[k];
          }
          if (is_covered(t, m, hashes)) {
            solutions.push_back(t);
          }
        }
      }
    }
    sort(solutions.begin(), solutions.end());
    solutions.erase(unique(solutions.begin(), solutions.end()),
                    solutions.end());
    cout << solutions.size() << endl;
    if (solutions.size() <= 5) {
      for (const auto &sol : solutions) {
        cout << sol << endl;
      }
    }
  }
  return 0;
}