Language: C++

#include <stdio.h>
#include <cmath>
#include <algorithm>
#include <cfloat>
#include <stack>
#include <queue>
#include <vector>
#include <string>
#include <iostream>
#include <set>
#include <map>
#include <time.h>
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){
		a = arg_a;
		g = arg_g;
		c = arg_c;
	}

	int a,g,c;
};

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 '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],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;
	}

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

	bool have_A,have_G,have_C,have_T;

	dp[CURRENT][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;
		int t;

		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;
					t = i-(a+g+c);
					if(t > num_T)continue;

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

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

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

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

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

		Updated.clear();
	}

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

	return 0;
}



Compiler output:
a.cc: In function 'int main()':
a.cc:229:64: error: invalid types 'll {aka long long int}[int]' for array subscript
  229 |                                         if(dp[CURRENT][a][g][c][t] == 0)continue;
      |                                                                ^