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

#include <algorithm>
#include <cstring>
#include <iostream>
#include <string>
#include <vector>

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

using namespace std;

const int M = 1000000007;

int main() {
  int na, nt, ng, nc, m;
  cin >> na >> nt >> ng >> nc >> m;
  string name[50];
  vector<string> elem[50];
  string dummy;
  getline(cin, dummy);
  rep(i, m) {
    string s;
    getline(cin, s);
    int n = s.length();
    for (int j = 0, p = 0; j <= n; j++) {
      if (j == n || s[j] == ' ') {
        if (p < j) {
          if (p == 0) {
            name[i] = s.substr(0, j - 1);
          } else {
            elem[i].push_back(s.substr(p, j - p));
          }
        }
        p = j + 1;
      }
    }
  }

  int len[50] = {}; // ループがないので各記号の長さは一意に決まる
  for (int i = m - 1; i >= 0; i--) {
    rep(j, elem[i].size()) {
      if (elem[i][j][0] == '[') { // 終端記号
        len[i]++;
      } else { // 非終端記号
        len[i] += len[find(name, name + m, elem[i][j]) - name];
      }
      len[i] = min(len[i], 201);
    }
  }
  if (len[0] != na + nt + ng + nc) {
    cout << 0 << endl;
    return 0;
  }

  // 構文規則を展開して終端記号だけで書く
  for (int i = m - 1; i >= 0; i--) {
    if (len[i] > 200)
      continue;

    vector<string> elem2;
    rep(j, elem[i].size()) {
      if (elem[i][j][0] == '[') { // 終端記号
        elem2.push_back(elem[i][j]);
      } else { // 非終端記号
        int id = find(name, name + m, elem[i][j]) - name;
        elem2.insert(elem2.end(), elem[id].begin(), elem[id].end());
      }
    }
    elem[i] = elem2;
  }

  static int dp[2][51][51][51];
  dp[0][0][0][0] = 1;
  rep(i, elem[0].size()) {
    int i1 = i % 2, i2 = 1 - i1;
    memset(dp[i2], 0, sizeof dp[i2]);

    bool ba = (elem[0][i].find('A') != -1);
    bool bt = (elem[0][i].find('T') != -1);
    bool bg = (elem[0][i].find('G') != -1);
    bool bc = (elem[0][i].find('C') != -1);

    rep(a, na + 1) rep(g, ng + 1) rep(t, nt + 1) {
      int c = i - a - g - t;
      if (ba && a + 1 <= na) {
        dp[i2][a + 1][t][g] += dp[i1][a][t][g];
        if (dp[i2][a + 1][t][g] >= M)
          dp[i2][a + 1][t][g] -= M;
      }
      if (bt && t + 1 <= nt) {
        dp[i2][a][t + 1][g] += dp[i1][a][t][g];
        if (dp[i2][a][t + 1][g] >= M)
          dp[i2][a][t + 1][g] -= M;
      }
      if (bg && g + 1 <= ng) {
        dp[i2][a][t][g + 1] += dp[i1][a][t][g];
        if (dp[i2][a][t][g + 1] >= M)
          dp[i2][a][t][g + 1] -= M;
      }
      if (bc && c + 1 <= nc) {
        dp[i2][a][t][g] += dp[i1][a][t][g];
        if (dp[i2][a][t][g] >= M)
          dp[i2][a][t][g] -= M;
      }
    }
  }

  cout << dp[elem[0].size() % 2][na][nt][ng] << endl;

  return 0;
}

Error: TLE

Fixed submission:

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <string>
#include <vector>

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

using namespace std;

const int M = 1000000007;

int main() {
  int na, nt, ng, nc, m;
  cin >> na >> nt >> ng >> nc >> m;
  string name[50];
  vector<string> elem[50];
  string dummy;
  getline(cin, dummy);
  rep(i, m) {
    string s;
    getline(cin, s);
    int n = s.length();
    for (int j = 0, p = 0; j <= n; j++) {
      if (j == n || s[j] == ' ') {
        if (p < j) {
          if (p == 0) {
            name[i] = s.substr(0, j - 1);
          } else {
            elem[i].push_back(s.substr(p, j - p));
          }
        }
        p = j + 1;
      }
    }
  }

  int len[50] = {}; // ループがないので各記号の長さは一意に決まる
  for (int i = m - 1; i >= 0; i--) {
    rep(j, elem[i].size()) {
      if (elem[i][j][0] == '[') { // 終端記号
        len[i]++;
      } else { // 非終端記号
        len[i] += len[find(name, name + m, elem[i][j]) - name];
      }
      len[i] = min(len[i], 201);
    }
  }
  if (len[0] != na + nt + ng + nc) {
    puts("0");
    return 0;
  }

  // 構文規則を展開して終端記号だけで書く
  for (int i = m - 1; i >= 0; i--) {
    if (len[i] > 200)
      continue;

    vector<string> elem2;
    rep(j, elem[i].size()) {
      if (elem[i][j][0] == '[') { // 終端記号
        elem2.push_back(elem[i][j]);
      } else { // 非終端記号
        int id = find(name, name + m, elem[i][j]) - name;
        elem2.insert(elem2.end(), elem[id].begin(), elem[id].end());
      }
    }
    elem[i] = elem2;
  }

  static int dp[2][51][51][51][51];
  dp[0][0][0][0][0] = 1;
  rep(i, elem[0].size()) {
    int i1 = i % 2, i2 = 1 - i1;
    memset(dp[i2], 0, sizeof dp[i2]);

    bool ba = (elem[0][i].find('A') != -1);
    bool bt = (elem[0][i].find('T') != -1);
    bool bg = (elem[0][i].find('G') != -1);
    bool bc = (elem[0][i].find('C') != -1);

    rep(a, na + 1) rep(g, ng + 1) rep(t, nt + 1) rep(c, nc + 1) {
      if (ba && a + 1 <= na) {
        dp[i2][a + 1][t][g][c] += dp[i1][a][t][g][c];
        if (dp[i2][a + 1][t][g][c] >= M)
          dp[i2][a + 1][t][g][c] -= M;
      }
      if (bt && t + 1 <= nt) {
        dp[i2][a][t + 1][g][c] += dp[i1][a][t][g][c];
        if (dp[i2][a][t + 1][g][c] >= M)
          dp[i2][a][t + 1][g][c] -= M;
      }
      if (bg && g + 1 <= ng) {
        dp[i2][a][t][g + 1][c] += dp[i1][a][t][g][c];
        if (dp[i2][a][t][g + 1][c] >= M)
          dp[i2][a][t][g + 1][c] -= M;
      }
      if (bc && c + 1 <= nc) {
        dp[i2][a][t][g][c + 1] += dp[i1][a][t][g][c];
        if (dp[i2][a][t][g][c + 1] >= M)
          dp[i2][a][t][g][c + 1] -= M;
      }
    }
  }

  printf("%d\\n", dp[elem[0].size() % 2][na][nt][ng][nc]);

  return 0;
}