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

#include <bits/stdc++.h>
using namespace std;

using VI = vector<int>;
using VVI = vector<VI>;
using PII = pair<int, int>;
using LL = long long;
using VL = vector<LL>;
using VVL = vector<VL>;
using PLL = pair<LL, LL>;
using VS = vector<string>;

#define ALL(a) begin((a)), end((a))
#define RALL(a) (a).rbegin(), (a).rend()
#define PB push_back
#define EB emplace_back
#define MP make_pair
#define SZ(a) int((a).size())
#define SORT(c) sort(ALL((c)))
#define RSORT(c) sort(RALL((c)))
#define UNIQ(c) (c).erase(unique(ALL((c))), end((c)))

#define FOR(i, a, b) for (int i = (a); i < (b); ++i)
#define REP(i, n) FOR(i, 0, n)

#define FF first
#define SS second
template <class S, class T> istream &operator>>(istream &is, pair<S, T> &p) {
  return is >> p.FF >> p.SS;
}
template <class S, class T>
ostream &operator<<(ostream &os, const pair<S, T> &p) {
  return os << p.FF << " " << p.SS;
}
template <class T> void maxi(T &x, T y) {
  if (x < y)
    x = y;
}
template <class T> void mini(T &x, T y) {
  if (x > y)
    x = y;
}

const double EPS = 1e-10;
const double PI = acos(-1.0);
const LL MOD = 1e9 + 7;

LL memo[2][51][51][51];
LL fact[2010], facti[2010];

LL powm(LL x, LL y, LL m) {
  if (y == 0)
    return 1;
  return powm(x * x % m, y / 2, m) * (y % 2 == 0 ? 1 : x) % m;
}

LL inv(LL x, LL m) { return powm(x, m - 2, m); }

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

  fact[0] = facti[0] = 1;
  REP(i, 2010 - 1) {
    fact[i + 1] = fact[i] * (i + 1) % MOD;
    facti[i + 1] = inv(fact[i + 1], MOD);
  }

  int A, T, G, C;
  cin >> A >> T >> G >> C;

  int Q;
  cin >> Q;
  map<string, int> id;
  VS rule_(Q);
  REP(i, Q) {
    string line;
    cin >> line;
    id[line.substr(0, SZ(line) - 1)] = i;
    getline(cin, line);
    rule_[i] = line;
  }

  VVI rule(Q);
  VVI cnt(Q, VI(16));
  REP(i, Q) {
    stringstream ss(rule_[i]);
    string var;
    while (ss >> var) {
      if (var[0] == '[') {
        int b = 0;
        for (char c : var) {
          if (c == 'A')
            b |= 1;
          if (c == 'T')
            b |= 2;
          if (c == 'G')
            b |= 4;
          if (c == 'C')
            b |= 8;
        }
        cnt[i][b]++;
      } else {
        rule[i].PB(id[var]);
      }
    }
  }

  int UB = A + T + G + C;
  for (int i = Q - 1; i >= 0; --i) {
    for (int x : rule[i])
      REP(b, 16) {
        cnt[i][b] += cnt[x][b];
        mini(cnt[i][b], UB + 1);
      }
  }

  if (accumulate(ALL(cnt[0]), 0) > UB) {
    cout << 0 << endl;
    return 0;
  }

  fill((LL *)memo, (LL *)memo + 2 * 51 * 51 * 51, 0);
  int crt = 0, nxt = 1, n = 0;
  memo[crt][0][0][0] = 1;
  REP(b, 16) {
    if (!cnt[0][b])
      continue;

    REP(i, cnt[0][b]) {
      fill((LL *)memo[nxt], (LL *)memo[nxt] + 51 * 51 * 51, 0);

      REP(a, A + 1) REP(t, T + 1) REP(g, G + 1) {
        int c = n - a - t - g;
        if (c < 0 || c > C)
          continue;
        if ((b >> 0 & 1) && a + 1 <= A)
          (memo[nxt][a + 1][t][g] += memo[crt][a][t][g]) %= MOD;
        if ((b >> 1 & 1) && t + 1 <= T)
          (memo[nxt][a][t + 1][g] += memo[crt][a][t][g]) %= MOD;
        if ((b >> 2 & 1) && g + 1 <= G)
          (memo[nxt][a][t][g + 1] += memo[crt][a][t][g]) %= MOD;
        if ((b >> 3 & 1) && c + 1 <= C) {
          (memo[nxt][a][t][g] += memo[crt][a][t][g]) %= MOD;
        }
      }
      ++n;
      swap(crt, nxt);
    }
  }
  cout << memo[crt][A][T][G] << endl;

  return 0;
}

Error: TLE

Fixed submission:

#include <bits/stdc++.h>
using namespace std;

using VI = vector<int>;
using VVI = vector<VI>;
using PII = pair<int, int>;
using LL = long long;
using VL = vector<LL>;
using VVL = vector<VL>;
using PLL = pair<LL, LL>;
using VS = vector<string>;

#define ALL(a) begin((a)), end((a))
#define RALL(a) (a).rbegin(), (a).rend()
#define PB push_back
#define EB emplace_back
#define MP make_pair
#define SZ(a) int((a).size())
#define SORT(c) sort(ALL((c)))
#define RSORT(c) sort(RALL((c)))
#define UNIQ(c) (c).erase(unique(ALL((c))), end((c)))

#define FOR(i, a, b) for (int i = (a); i < (b); ++i)
#define REP(i, n) FOR(i, 0, n)

#define FF first
#define SS second
template <class S, class T> istream &operator>>(istream &is, pair<S, T> &p) {
  return is >> p.FF >> p.SS;
}
template <class S, class T>
ostream &operator<<(ostream &os, const pair<S, T> &p) {
  return os << p.FF << " " << p.SS;
}
template <class T> void maxi(T &x, T y) {
  if (x < y)
    x = y;
}
template <class T> void mini(T &x, T y) {
  if (x > y)
    x = y;
}

const double EPS = 1e-10;
const double PI = acos(-1.0);
const LL MOD = 1e9 + 7;

LL memo[2][51][51][51][51];
LL fact[2010], facti[2010];

LL powm(LL x, LL y, LL m) {
  if (y == 0)
    return 1;
  return powm(x * x % m, y / 2, m) * (y % 2 == 0 ? 1 : x) % m;
}

LL inv(LL x, LL m) { return powm(x, m - 2, m); }

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

  fact[0] = facti[0] = 1;
  REP(i, 2010 - 1) {
    fact[i + 1] = fact[i] * (i + 1) % MOD;
    facti[i + 1] = inv(fact[i + 1], MOD);
  }

  int A, T, G, C;
  cin >> A >> T >> G >> C;

  int Q;
  cin >> Q;
  map<string, int> id;
  VS rule_(Q);
  REP(i, Q) {
    string line;
    cin >> line;
    id[line.substr(0, SZ(line) - 1)] = i;
    getline(cin, line);
    rule_[i] = line;
  }

  VVI rule(Q);
  VVI cnt(Q, VI(16));
  REP(i, Q) {
    stringstream ss(rule_[i]);
    string var;
    while (ss >> var) {
      if (var[0] == '[') {
        int b = 0;
        for (char c : var) {
          if (c == 'A')
            b |= 1;
          if (c == 'T')
            b |= 2;
          if (c == 'G')
            b |= 4;
          if (c == 'C')
            b |= 8;
        }
        cnt[i][b]++;
      } else {
        rule[i].PB(id[var]);
      }
    }
  }

  int UB = A + T + G + C;
  for (int i = Q - 1; i >= 0; --i) {
    for (int x : rule[i])
      REP(b, 16) {
        cnt[i][b] += cnt[x][b];
        mini(cnt[i][b], UB + 1);
      }
  }

  if (accumulate(ALL(cnt[0]), 0) > UB) {
    cout << 0 << endl;
    return 0;
  }

  // REP(i,16) cout << bitset<4>(i) << ": "<<cnt[0][i] << endl;

  fill((LL *)memo, (LL *)memo + 2 * 51 * 51 * 51 * 51, 0);
  int crt = 0, nxt = 1;
  memo[crt][0][0][0][0] = 1;
  REP(b, 16) {
    if (!cnt[0][b])
      continue;

    REP(i, cnt[0][b]) {
      fill((LL *)memo[nxt], (LL *)memo[nxt] + 51 * 51 * 51 * 51, 0);

      REP(a, A + 1) REP(t, T + 1) REP(g, G + 1) REP(c, C + 1) {
        (memo[nxt][a][t][g][c] += memo[crt][a][t][g][c]) %= MOD;
        if ((b >> 0 & 1) && a + 1 <= A)
          (memo[nxt][a + 1][t][g][c] += memo[crt][a][t][g][c]) %= MOD;
        if ((b >> 1 & 1) && t + 1 <= T)
          (memo[nxt][a][t + 1][g][c] += memo[crt][a][t][g][c]) %= MOD;
        if ((b >> 2 & 1) && g + 1 <= G)
          (memo[nxt][a][t][g + 1][c] += memo[crt][a][t][g][c]) %= MOD;
        if ((b >> 3 & 1) && c + 1 <= C)
          (memo[nxt][a][t][g][c + 1] += memo[crt][a][t][g][c]) %= MOD;
      }
      swap(crt, nxt);
    }
  }
  cout << memo[crt][A][T][G][C] << endl;

  return 0;
}