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

#include <bitset>
#include <cstdlib>
#include <iostream>
#include <sstream>
#include <unordered_map>
#include <vector>
using namespace std;

constexpr int MAX_M = 50;
constexpr int MAX_N = 50;
constexpr int mod = 1000000007;

enum { A, T, G, C };

int na, nt, ng, nc;
int m;

int dp[MAX_N * 4 + 1][MAX_N + 1][MAX_N + 1][MAX_N + 1];
vector<string> rules[MAX_M];
unordered_map<string, int> converter;

int idx[128];

int len = 0;
vector<bitset<4>> sequence;

inline void calc(int v) {
  for (const auto &s : rules[v]) {
    if (s[0] == '[') {
      if (++len > na + nt + ng + nc)
        throw "too long";

      bitset<4> tmp;
      for (unsigned i = 1; i < s.size() - 1; ++i) {
        tmp.set(idx[static_cast<int>(s[i])]);
      }
      sequence.emplace_back(tmp);
    } else {
      calc(converter[s]);
    }
  }
}

int solve() {
  try {
    calc(0);
  } catch (...) {
    return 0;
  }

  if (len < na + nt + ng + nc)
    return 0;

  dp[0][0][0][0] = 1;

  for (int i = 0; i < len; ++i) {
    const auto &b = sequence[i];

    for (int a = 0; a <= min(na, i); ++a) {
      for (int t = 0; t <= min(nt, i - a); ++t) {
        for (int g = 0; g <= min(ng, i - (a + t)); ++g) {
          const int c = i - (a + t + g);

          if (b.test(A) && a < na) {
            dp[i + 1][a + 1][t][g] += dp[i][a][t][g];
            if (dp[i + 1][a + 1][t][g] >= mod)
              dp[i + 1][a + 1][t][g] -= mod;
          }
          if (b.test(T) && t < nt) {
            dp[i + 1][a][t + 1][g] += dp[i][a][t][g];
            if (dp[i + 1][a][t + 1][g] >= mod)
              dp[i + 1][a][t + 1][g] -= mod;
          }
          if (b.test(G) && g < ng) {
            dp[i + 1][a][t][g + 1] += dp[i][a][t][g];
            if (dp[i + 1][a][t][g + 1] >= mod)
              dp[i + 1][a][t][g + 1] -= mod;
          }
          if (b.test(C) && c < nc) {
            dp[i + 1][a][t][g] += dp[i][a][t][g];
            if (dp[i + 1][a][t][g] >= mod)
              dp[i + 1][a][t][g] -= mod;
          }
        }
      }
    }
  }

  return dp[len][na][nt][ng];
}

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

  idx[static_cast<int>('A')] = A;
  idx[static_cast<int>('T')] = T;
  idx[static_cast<int>('G')] = G;
  idx[static_cast<int>('C')] = C;

  cin >> na >> nt >> ng >> nc;
  sequence.reserve(na + nt + ng + nc);

  cin >> m;
  cin.ignore();

  for (int i = 0; i < m; ++i) {
    string line;
    getline(cin, line);

    istringstream iss(line);

    string symbol;
    iss >> symbol;

    symbol = symbol.substr(0, symbol.size() - 1);
    converter[symbol] = i;

    for (string in; iss >> in;) {
      rules[i].emplace_back(in);
    }
  }

  cout << solve() << endl;

  return EXIT_SUCCESS;
}

Error: TLE

Fixed submission:

#include <cassert>
#include <cstdlib>
#include <iostream>
#include <map>
#include <sstream>
#include <tuple>
#include <unordered_map>
#include <vector>
using namespace std;

constexpr int MAX_M = 50;
constexpr int mod = 1000000007;

enum { A, T, G, C };

int na, nt, ng, nc;
int m;

vector<string> rules[MAX_M];
unordered_map<string, int> converter;

typedef tuple<int, int, int> state;

int len = 0;
map<state, int> dp;
const unordered_map<char, state> base{{'A', state(1, 0, 0)},
                                      {'T', state(0, 1, 0)},
                                      {'G', state(0, 0, 1)},
                                      {'C', state(0, 0, 0)}};

inline state operator+(const state &s1, const state &s2) {
  return state(get<A>(s1) + get<A>(s2), get<T>(s1) + get<T>(s2),
               get<G>(s1) + get<G>(s2));
}

inline bool over(const state &s) {
  const int c = len - (get<A>(s) + get<T>(s) + get<G>(s));
  return get<A>(s) > na || get<T>(s) > nt || get<G>(s) > ng || c > nc;
}

inline void calc(int v) {
  for (const auto &s : rules[v]) {
    if (s[0] == '[') {
      if (++len > na + nt + ng + nc) {
        dp.clear();
        throw "too long";
      }

      map<state, int> next;
      for (int i = 1; i < static_cast<int>(s.size()) - 1; ++i) {
        const state &inc = base.at(s[i]);
        for (const auto &e : dp) {
          const state t = e.first + inc;
          if (!over(t)) {
            auto &target = next[t];
            target += e.second;
            if (target >= mod)
              next[t] -= mod;
          }
        }
      }

      dp = move(next);
    } else {
      calc(converter[s]);
    }
  }
}

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

  cin >> na >> nt >> ng >> nc;

  cin >> m;
  cin.ignore();

  for (int i = 0; i < m; ++i) {
    string line;
    getline(cin, line);

    istringstream iss(line);

    string symbol;
    iss >> symbol;

    symbol = symbol.substr(0, symbol.size() - 1);
    converter[symbol] = i;

    for (string in; iss >> in;) {
      rules[i].emplace_back(in);
    }
  }

  dp[state(0, 0, 0)] = 1;
  try {
    calc(0);
  } catch (...) {
    // do nothing
  }

  cout << dp[state(na, nt, ng)] << endl;

  return EXIT_SUCCESS;
}