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

#include "bits/stdc++.h"
#include <unordered_map>
#include <unordered_set>
#pragma warning(disable : 4996)
using namespace std;
using ld = long double;
template <class T> using Table = vector<vector<T>>;

struct UnionFind {
  vector<int> data;
  UnionFind(int size) : data(size, -1) {}
  bool unionSet(int x, int y) {
    x = root(x);
    y = root(y);
    if (x != y) {
      if (data[y] < data[x])
        swap(x, y);
      data[x] += data[y];
      data[y] = x;
    }
    return x != y;
  }
  bool findSet(int x, int y) { return root(x) == root(y); }
  int root(int x) { return data[x] < 0 ? x : data[x] = root(data[x]); }
  int size(int x) { return -data[root(x)]; }
};

bool dp[1 << 12][5001];
int main() {
  while (1) {
    int n, m;
    cin >> n >> m;
    if (!n)
      break;
    vector<string> elems;
    for (int i = 0; i < n; ++i) {
      string st;
      cin >> st;
      elems.push_back(st);
    }
    UnionFind uf(n);
    for (int i = 0; i < n; ++i) {
      for (int j = i + 1; j < n; ++j) {
        if (elems[i] == elems[j])
          uf.unionSet(i, j);
      }
    }
    long long int waru = 1;
    {
      set<int> used;
      for (int i = 0; i < n; ++i) {
        if (used.find(uf.root(i)) == used.end()) {
          used.emplace(uf.root(i));
          int num = uf.size(i);
          while (num >= 2)
            waru *= num--;
        }
      }
    }

    string text;
    for (int i = 0; i < m; ++i) {
      string st;
      cin >> st;
      text += st;
    }
    vector<vector<int>> oks(n, vector<int>(text.size()));
    for (int e = 0; e < elems.size(); ++e) {
      for (int i = 0; i <= text.size() - elems[e].size(); ++i) {
        if (elems[e] == text.substr(i, elems[e].size())) {
          oks[e][i] = true;
        }
      }
    }
    memset(dp, false, sizeof(dp));
    for (int i = 0; i < 5001; ++i) {
      dp[0][i] = true;
    }
    set<int> ans;
    for (int j = 0; j < text.size(); ++j) {
      /*if (j % 100 == 0) {
              num++;
              for (int j = 0; j < 1 << 12; ++j) {

              }
              for (int j = 0; j < 1 << 12; ++j) {
                      for (int i = 0; i < 100; ++i) {
                              dp[0][i] = 1;
                              dp[j][i] = dp[j][i + 100];
                      }
                      for (int i = 100; i < 501; ++i) {
                              dp[0][i] = 1;
                              dp[j][i] = 0;
                      }
              }
      }*/
      for (int i = 0; i < 1 << n; ++i) {
        bitset<12> uses(i);
        for (int e = 0; e < n; ++e) {
          if (oks[e][j] && !uses[e] && dp[i][j]) {
            const int next = j + elems[e].size();
            if (next <= text.size()) {
              uses[e] = true;
              if (uses.count() == n)
                ans.emplace(next);
              dp[uses.to_ulong()][next] = true;
              uses[e] = false;
            }
          }
        }
      }
    }
    cout << ans.size() << endl;
  }
  return 0;
}

Error: TLE

Fixed submission:

#include "bits/stdc++.h"
#include <unordered_map>
#include <unordered_set>
#pragma warning(disable : 4996)
using namespace std;
using ld = long double;
template <class T> using Table = vector<vector<T>>;

struct UnionFind {
  vector<int> data;
  UnionFind(int size) : data(size, -1) {}
  bool unionSet(int x, int y) {
    x = root(x);
    y = root(y);
    if (x != y) {
      if (data[y] < data[x])
        swap(x, y);
      data[x] += data[y];
      data[y] = x;
    }
    return x != y;
  }
  bool findSet(int x, int y) { return root(x) == root(y); }
  int root(int x) { return data[x] < 0 ? x : data[x] = root(data[x]); }
  int size(int x) { return -data[root(x)]; }
};

long long int dp[1 << 12][501];
int main() {
  while (1) {
    int n, m;
    cin >> n >> m;
    if (!n)
      break;
    vector<string> elems;
    for (int i = 0; i < n; ++i) {
      string st;
      cin >> st;
      elems.push_back(st);
    }
    UnionFind uf(n);
    for (int i = 0; i < n; ++i) {
      for (int j = i + 1; j < n; ++j) {
        if (elems[i] == elems[j])
          uf.unionSet(i, j);
      }
    }
    long long int waru = 1;
    {
      set<int> used;
      for (int i = 0; i < n; ++i) {
        if (used.find(uf.root(i)) == used.end()) {
          used.emplace(uf.root(i));
          int num = uf.size(i);
          while (num >= 2)
            waru *= num--;
        }
      }
    }

    string text;
    for (int i = 0; i < m; ++i) {
      string st;
      cin >> st;
      text += st;
    }
    vector<vector<int>> oks(n, vector<int>(text.size()));
    for (int e = 0; e < elems.size(); ++e) {
      for (int i = 0; i <= text.size() - elems[e].size(); ++i) {
        if (elems[e] == text.substr(i, elems[e].size())) {
          oks[e][i] = true;
        }
      }
    }
    memset(dp, 0, sizeof(dp));
    for (int i = 0; i < 501; ++i) {
      dp[0][i] = 1;
    }
    long long int ans = 0;
    int num = -1;
    for (int j = 0; j < text.size(); ++j) {
      if (j % 100 == 0) {
        num++;
        for (int j = 0; j < 1 << 12; ++j) {
        }
        for (int j = 0; j < 1 << 12; ++j) {
          for (int i = 0; i < 100; ++i) {
            dp[0][i] = 1;
            dp[j][i] = dp[j][i + 100];
          }
          for (int i = 100; i < 501; ++i) {
            dp[0][i] = 1;
            dp[j][i] = 0;
          }
        }
      }
      for (int i = 0; i < 1 << n; ++i) {
        bitset<12> uses(i);
        for (int e = 0; e < n; ++e) {
          if (oks[e][j] && !uses[e]) {
            const int next = j + elems[e].size();
            if (next <= text.size()) {
              uses[e] = true;
              if (uses.count() == n)
                ans += dp[i][j - num * 100];
              dp[uses.to_ulong()][next - num * 100] += dp[i][j - num * 100];
              uses[e] = false;
            }
          }
        }
      }
    }
    cout << ans / waru << endl;
  }
  return 0;
}