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

#include <algorithm>
#include <cfloat>
#include <cmath>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <stdio.h>
#include <string>
#include <time.h>
#include <vector>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;

#define A 3
#define T 2
#define G 1
#define C 0

struct Info {
  char name[21];
  vector<int> V;
};

int POW[5];
int num_A, num_T, num_G, num_C, M;
char input_str[50][2001];
ll dp[2][51][51][51];
bool is_over[50];
Info info[50];

bool strCmp(char *base, char *comp) {
  int length1, length2;
  for (length1 = 0; base[length1] != '\\0'; length1++)
    ;
  for (length2 = 0; comp[length2] != '\\0'; length2++)
    ;
  if (length1 != length2)
    return false;

  for (int i = 0; base[i] != '\\0'; i++) {
    if (base[i] != comp[i])
      return false;
  }
  return true;
}

void strcpy(char *to, char *str) {
  for (int i = 0; str[i] != '\\0'; i++) {
    to[i] = str[i];
    to[i + 1] = '\\0';
  }
}

int makeCode(char work[5]) {

  int res = 0;

  for (int i = 0; work[i] != '\\0'; i++) {
    switch (work[i]) {
    case 'A':
      res += POW[A];
      break;
    case 'T':
      res += POW[T];
      break;
    case 'G':
      res += POW[G];
      break;
    case 'C':
      res += POW[C];
      break;
    }
  }
  return res;
}

int main() {

  for (int i = 0; i < 5; i++)
    POW[i] = pow(2, i);

  scanf("%d %d %d %d", &num_A, &num_T, &num_G, &num_C);
  scanf("%d", &M);

  getchar();
  for (int i = 0; i < M; i++) {
    fgets(input_str[i], 2000, stdin);
    is_over[i] = false;
  }

  char tmp_name[21], work[5];
  int index, work_index;

  // 非終端記号は、自分より前に入力された非終端記号を含まないので、逆からループ
  for (int i = M - 1; i >= 0; i--) {
    // 非終端記号の名前の取得
    for (index = 0; input_str[i][index] != ':'; index++) {
      tmp_name[index] = input_str[i][index];
    }
    tmp_name[index] = '\\0';

    strcpy(info[i].name, tmp_name);

    index++; //':'の次にインデックスを進める

    while (input_str[i][index] != '\\0' && input_str[i][index] != '\\n') {
      while (input_str[i][index] == ' ')
        index++; // 空白を読み飛ばす

      if (input_str[i][index] == '\\0' || input_str[i][index] == '\\n')
        break;

      if (input_str[i][index] == '[') { // 終端記号

        index++;
        work_index = 0;
        while (input_str[i][index] != ']') {
          work[work_index++] = input_str[i][index];
          index++;
        }
        work[work_index] = '\\0';

        info[i].V.push_back(makeCode(work)); // コードを格納

        index++;

      } else { // 非終端記号:既にinfoに情報が格納されているはずなので、特定してVをコピーする

        for (int k = 0;
             input_str[i][index] != '\\0' && input_str[i][index] != '\\n' &&
             input_str[i][index] != ' ';
             k++, index++) {
          tmp_name[k] = input_str[i][index];
          tmp_name[k + 1] = '\\0';
        }

        for (int k = i + 1; k < M; k++) {
          if (strCmp(info[k].name, tmp_name)) {
            if (is_over[k]) {
              is_over[i] = true;
              break;
            }
            for (int p = 0; p < info[k].V.size(); p++) { // AGCTコードをコピー
              info[i].V.push_back(info[k].V[p]);
              if (info[i].V.size() > num_A + num_T + num_G + num_C) {
                is_over[i] = true;
                break;
              }
            }
            break;
          }
          if (is_over[i])
            break;
        }

        if (info[i].V.size() > num_A + num_T + num_G + num_C) {
          is_over[i] = true;
        }
      }
    }
  }

  if (is_over[0] == true ||
      info[0].V.size() !=
          num_A + num_T + num_G +
              num_C) { // 文字列1のコード数と、A,G,C,Tの使用回数の合計が合わなければreturn
    printf("0\\n");
    return 0;
  }

  int CURRENT = 0, NEXT = 1;

  for (int a = 0; a <= num_A; a++) {
    for (int t = 0; t <= num_T; t++) {
      for (int g = 0; g <= num_G; g++) {
        dp[CURRENT][a][t][g] = 0;
        dp[NEXT][a][t][g] = 0;
      }
    }
  }

  bool have_A, have_T, have_G, have_C;

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

  for (int i = 0; i < info[0].V.size(); i++) {

    // printf("i:%d\\n",i);

    if (info[0].V[i] & (1 << A)) {
      // printf("A\\n");
      have_A = true;
    } else {
      have_A = false;
    }

    if (info[0].V[i] & (1 << T)) {
      // printf("T\\n");
      have_T = true;
    } else {
      have_T = false;
    }

    if (info[0].V[i] & (1 << G)) {
      // printf("G\\n");
      have_G = true;
    } else {
      have_G = false;
    }

    if (info[0].V[i] & (1 << C)) {
      // printf("C\\n");
      have_C = true;
    } else {
      have_C = false;
    }

    int c;

    for (int a = 0; a <= min(num_A, i); a++) {
      for (int t = 0; t <= min(num_T, i); t++) {
        if (a + t > i)
          break;
        for (int g = 0; g <= min(num_G, i); g++) {
          if (a + t + g > i)
            break;
          c = i - (a + t + g);
          if (c > num_C)
            continue;

          if (dp[CURRENT][a][t][g] == 0)
            continue;

          if (have_A == true && a < num_A) {
            dp[NEXT][a + 1][t][g] += dp[CURRENT][a][t][g];
            dp[NEXT][a + 1][t][g] %= MOD;
          }

          if (have_T == true && t < num_T) {
            // printf("i:%d a;%d g:%d c:%d t:%d
            // dp:%lld\\n",i,a,g,c,t,dp[CURRENT][a][t][g]);
            dp[NEXT][a][t + 1][g] += dp[CURRENT][a][t][g];
            dp[NEXT][a][t + 1][g] %= MOD;
          }

          if (have_G == true && g < num_G) {
            dp[NEXT][a][t][g + 1] += dp[CURRENT][a][t][g];
            dp[NEXT][a][t][g + 1] %= MOD;
          }

          if (have_C == true && c < num_C) {
            // printf("i:%d a;%d g:%d c:%d t:%d
            // dp:%lld\\n",i,a,g,c,t,dp[CURRENT][a][t][g]);
            dp[NEXT][a][t][g] += dp[CURRENT][a][t][g];
            dp[NEXT][a][t][g] %= MOD;
          }
        }
      }
    }
    swap(NEXT, CURRENT);

    for (int a = 0; a <= num_A; a++) {
      for (int t = 0; t <= num_T; t++) {
        if (a + t > i)
          break;
        for (int g = 0; g <= num_G; g++) {
          if (a + t + g > i)
            break;
          dp[NEXT][a][t][g] = 0;
        }
      }
    }
  }

  printf("%lld\\n", dp[CURRENT][num_A][num_T][num_G] % MOD);

  return 0;
}


Error: MLE

Fixed submission:

#include <algorithm>
#include <cfloat>
#include <cmath>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <stdio.h>
#include <string>
#include <time.h>
#include <vector>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;

#define A 3
#define G 2
#define C 1
#define T 0

enum Type {
  CURRENT,
  NEXT,
};

struct Info {
  char name[21];
  vector<int> V; // 遺伝子の文字列
};

struct Data {
  Data(int arg_a, int arg_g, int arg_c, int arg_t) {
    a = arg_a;
    g = arg_g;
    c = arg_c;
    t = arg_t;
  }

  int a, g, c, t;
};

int POW[5];
int num_A, num_T, num_G, num_C, M;
char input_str[50][1001];
ll dp[2][51][51][51][51];
bool is_over[50];
Info info[50];

bool strCmp(char *base, char *comp) {
  int length1, length2;
  for (length1 = 0; base[length1] != '\\0'; length1++)
    ;
  for (length2 = 0; comp[length2] != '\\0'; length2++)
    ;
  if (length1 != length2)
    return false;

  for (int i = 0; base[i] != '\\0'; i++) {
    if (base[i] != comp[i])
      return false;
  }
  return true;
}

void strcpy(char *to, char *str) {
  for (int i = 0; str[i] != '\\0'; i++) {
    to[i] = str[i];
    to[i + 1] = '\\0';
  }
}

// 終端記号をコード化する
int makeCode(char work[5]) {

  int res = 0;

  for (int i = 0; work[i] != '\\0'; i++) {
    switch (work[i]) {
    case 'A':
      res += POW[A];
      break;
    case 'G':
      res += POW[G];
      break;
    case 'C':
      res += POW[C];
      break;
    case 'T':
      res += POW[T];
      break;
    }
  }
  return res;
}

int main() {

  for (int i = 0; i < 5; i++)
    POW[i] = pow(2, i);

  scanf("%d %d %d %d", &num_A, &num_T, &num_G, &num_C);
  scanf("%d", &M);

  getchar();
  for (int i = 0; i < M; i++) {
    fgets(input_str[i], 1000, stdin);
    is_over[i] = false;
  }

  char tmp_name[21], work[5];
  int index, work_index;

  // 非終端記号は、自分より前に入力された非終端記号を含まないので、逆からループ
  for (int i = M - 1; i >= 0; i--) {
    // 非終端記号の名前の取得
    for (index = 0; input_str[i][index] != ':'; index++) {
      tmp_name[index] = input_str[i][index];
    }
    tmp_name[index] = '\\0';

    strcpy(info[i].name, tmp_name);

    // printf("i:%d name:%s\\n",i,info[i].name);
    index++; //':'の次にインデックスを進める

    while (input_str[i][index] != '\\0' && input_str[i][index] != '\\n') {
      while (input_str[i][index] == ' ')
        index++; // 空白を読み飛ばす

      if (input_str[i][index] == '\\0' || input_str[i][index] == '\\n')
        break;

      if (input_str[i][index] == '[') { // 終端記号

        // printf("終端記号\\n");

        index++;
        work_index = 0;
        while (input_str[i][index] != ']') {
          work[work_index++] = input_str[i][index];
          index++;
        }
        work[work_index] = '\\0';

        info[i].V.push_back(makeCode(work)); // コードを格納

        index++;

      } else { // 非終端記号:既にinfoに情報が格納されているはずなので、特定してVをコピーする

        // printf("非終端記号:%c\\n",input_str[i][index]);

        for (int k = 0;
             input_str[i][index] != '\\0' && input_str[i][index] != '\\n' &&
             input_str[i][index] != ' ';
             k++, index++) {
          tmp_name[k] = input_str[i][index];
          tmp_name[k + 1] = '\\0';
        }

        /*printf("tmp_name:%s\\n",tmp_name);
        for(int k = 0; tmp_name[k] != '\\0' && k < 30; k++){
                printf("tmp_name[%d]:%c\\n",k,tmp_name[k]);
        }*/

        for (int k = i + 1; k < M; k++) {
          // printf("info[%d].name:%s\\n",k,info[k].name);
          if (strCmp(info[k].name, tmp_name)) {
            // printf("info[%d]とマッチ\\n",k);
            if (is_over[k]) {
              // printf("%dがサイズ超過\\n",k);
              is_over[i] = true;
              break;
            }
            for (int p = 0; p < info[k].V.size(); p++) { // AGCTコードをコピー
              info[i].V.push_back(info[k].V[p]);
              if (info[i].V.size() > num_A + num_T + num_G + num_C) {
                is_over[i] = true;
                break;
              }
            }
            break;
          }
          if (is_over[i])
            break;
        }

        if (info[i].V.size() > num_A + num_T + num_G + num_C) {
          // printf("%dがサイズ超過\\n",i);
          is_over[i] = true;
        }
      }
    }
  }

  /*	for(int i = 0; i < M; i++){
                  printf("name[%d]:%s\\n",i,info[i].name);
                  for(int k = 0; k < info[i].V.size();k++){
                          printf("Code[%d]: %d\\n",k,info[i].V[k]);
                  }
          }*/

  if (is_over[0] == true ||
      info[0].V.size() !=
          num_A + num_T + num_G +
              num_C) { // 文字列1のコード数と、A,G,C,Tの使用回数の合計が合わなければreturn
    printf("0\\n");
    return 0;
  }

  for (int a = 0; a <= num_A; a++) {
    for (int g = 0; g <= num_G; g++) {
      for (int c = 0; c <= num_C; c++) {
        for (int t = 0; t <= num_T; t++) {
          dp[CURRENT][a][g][c][t] = 0;
          dp[NEXT][a][g][c][t] = 0;
        }
      }
    }
  }

  bool have_A, have_G, have_C, have_T;

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

  for (int i = 0; i < info[0].V.size(); i++) {

    if (info[0].V[i] & (1 << A)) {
      have_A = true;
    } else {
      have_A = false;
    }

    if (info[0].V[i] & (1 << G)) {
      have_G = true;
    } else {
      have_G = false;
    }

    if (info[0].V[i] & (1 << C)) {
      have_C = true;
    } else {
      have_C = false;
    }

    if (info[0].V[i] & (1 << T)) {
      have_T = true;
    } else {
      have_T = false;
    }

    vector<Data> Updated;

    for (int a = 0; a <= min(num_A, i); a++) {
      for (int g = 0; g <= min(num_G, i); g++) {
        if (a + g > i)
          break;
        for (int c = 0; c <= min(num_C, i); c++) {
          if (a + g + c > i)
            break;
          for (int t = 0; t <= min(num_T, i); t++) {
            if (a + g + c + t > i)
              break;
            if (dp[CURRENT][a][g][c][t] == 0)
              continue;

            if (have_A == true && a < num_A) {
              dp[NEXT][a + 1][g][c][t] += dp[CURRENT][a][g][c][t];
              dp[NEXT][a + 1][g][c][t] %= MOD;
              Updated.push_back(Data(a + 1, g, c, t));
            }

            if (have_G == true && g < num_G) {
              dp[NEXT][a][g + 1][c][t] += dp[CURRENT][a][g][c][t];
              dp[NEXT][a][g + 1][c][t] %= MOD;
              Updated.push_back(Data(a, g + 1, c, t));
            }

            if (have_C == true && c < num_C) {
              dp[NEXT][a][g][c + 1][t] += dp[CURRENT][a][g][c][t];
              dp[NEXT][a][g][c + 1][t] %= MOD;
              Updated.push_back(Data(a, g, c + 1, t));
            }

            if (have_T == true && t < num_T) {
              dp[NEXT][a][g][c][t + 1] += dp[CURRENT][a][g][c][t];
              dp[NEXT][a][g][c][t + 1] %= MOD;
              Updated.push_back(Data(a, g, c, t + 1));
            }
          }
        }
      }
    }
    for (int k = 0; k < Updated.size(); k++) {
      dp[CURRENT][Updated[k].a][Updated[k].g][Updated[k].c][Updated[k].t] =
          dp[NEXT][Updated[k].a][Updated[k].g][Updated[k].c][Updated[k].t];
    }

    Updated.clear();
  }

  printf("%lld\\n", dp[CURRENT][num_A][num_G][num_C][num_T] % MOD);

  return 0;
}