Problem:
問題名 DNA
遺伝子は、
A
,
T
,
G
,
C
からなる文字列です。
この世界の遺伝子は奇妙なことに、ある構文規則に従うことが知られています。
構文規則は、次のような形で与えられます。
非終端記号1: 記号1_1 記号1_2 ... 記号1_n1
非終端記号2: 記号2_1 記号2_2 ... 記号2_n2
...
非終端記号m: 記号m_1 記号m_2 ... 記号m_nm
記号は非終端記号または終端記号のどちらかです。
非終端記号は小文字文字列で表され、終端記号は
A
,
T
,
G
,
C
のうちのいくつかの文字が、"
[
"と"
]
"に囲まれた文字列で表されます。
構文規則の例は次のようになります。
dna: a a b b
a: [AT]
b: [GC]
"
非終端記号i: 記号i_1 記号i_2 ... 記号i_ni
" を非終端記号
i
のルールと呼び、ルールは、構文規則に現れる各非終端記号に対して、ちょうど 1 つづつ存在します。
文字列
s
が非終端記号
i
に「
マッチする
」とは、
s = s
1
+ s
2
+ ... + s
ni
となるような
s
の部分文字列
{s
j
}
が存在し、
s
j
(
1 ≤ j ≤ n
i
)がルール内の記号
j
にマッチすることをいいます。
文字列
s
が終端記号に「
マッチする
」とは、文字列が 1 文字からなり、その文字が終端記号を表す文字列に含まれることをいいます。
文字列が構文規則に従うとは、非終端記号
1
にその文字列がマッチすることをいいます。
ルール
i
は、記号のうちに、非終端記号
j
(
j ≤ i
) を含みません。
構文規則と、4つの整数
Na
,
Nt
,
Ng
,
Nc
が与えられます。
構文規則に従い、A をちょうど
Na
個、T をちょうど
Nt
個、G をちょうど
Ng
個、C をちょうど
Nc
個含むような遺伝子の総数を 1,000,000,007 で割った余りを求めなさい。
Input
Na
Nt
Ng
Nc
m
非終端記号1: 記号
1
1
記号
1
2
... 記号
1
n1
非終端記号2: 記号
2
1
記号
2
2
... 記号
2
n2
...
非終端記号
m
: 記号
m
1
記号
m
2
... 記号
m
nm
0 ≤ Na, Nt, Ng, Nc ≤ 50
1 ≤ m ≤ 50
1 ≤ ni ≤ 10
1 ≤
記号を表す文字列の長さ
≤ 20
(※記号にマッチする文字列の長さではないことに注意)
Output
総数を 1,000,000,007 で割った余り
Sample Input 1
1 0 1 0
3
dna: a b
a: [AT]
b: [GC]
Output for the Sample Input 1
1
"AG"の一つです。
Sample Input 2
1 1 1 2
1
k: [ATG] [ATG] [ATG] [C] [C]
Output for the Sample Input 2
6
"ATGCC", "AGTCC", "TAGCC", "TGACC", "GATCC", "GTACC"の6つです。
Sample Input 3
3 1 1 1
3
inv: at b b b
at: [ATG] b
b: [C]
Output for the Sample Input 3
0

Submitted solutions:

code_snippet: #include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b) for (int i = (int)(a); i < (int)(b); i++)
#define rrep(i, a, b) for (int i = (int)(b)-1; i >= (int)(a); i--)
#define ALL(v) (v).begin(), (v).end()
#define UNIQUE(v) sort(ALL(v)), (v).erase(unique(ALL(v)), (v).end())
#define SZ(v) (int)v.size()
#define MIN(v) *min_element(ALL(v))
#define MAX(v) *max_element(ALL(v))
#define LB(v, x) int(lower_bound(ALL(v), (x)) - (v).begin())
#define UB(v, x) int(upper_bound(ALL(v), (x)) - (v).begin())

using uint = unsigned int;
using ll = long long int;
using ull = unsigned long long;
using i128 = __int128_t;
using u128 = __uint128_t;
const int inf = 0x3fffffff;
const ll INF = 0x1fffffffffffffff;

template <typename T> inline bool chmax(T &a, T b) {
    if (a < b) {
        a = b;
        return 1;
    }
    return 0;
}
template <typename T> inline bool chmin(T &a, T b) {
    if (a > b) {
        a = b;
        return 1;
    }
    return 0;
}
template <typename T, typename U> T ceil(T x, U y) {
    assert(y != 0);
    if (y < 0)
        x = -x, y = -y;
    return (x > 0 ? (x + y - 1) / y : x / y);
}
template <typename T, typename U> T floor(T x, U y) {
    assert(y != 0);
    if (y < 0)
        x = -x, y = -y;
    return (x > 0 ? x / y : (x - y + 1) / y);
}
template <typename T> int popcnt(T x) {
    return __builtin_popcountll(x);
}
template <typename T> int topbit(T x) {
    return (x == 0 ? -1 : 63 - __builtin_clzll(x));
}
template <typename T> int lowbit(T x) {
    return (x == 0 ? -1 : __builtin_ctzll(x));
}

template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
    os << "P(" << p.first << ", " << p.second << ")";
    return os;
}
template <typename T> ostream &operator<<(ostream &os, const vector<T> &vec) {
    os << "{";
    for (int i = 0; i < vec.size(); i++) {
        os << vec[i] << (i + 1 == vec.size() ? "" : ", ");
    }
    os << "}";
    return os;
}
template <typename T, typename U>
ostream &operator<<(ostream &os, const map<T, U> &map_var) {
    os << "{";
    for (auto itr = map_var.begin(); itr != map_var.end(); itr++) {
        os << "(" << itr->first << ", " << itr->second << ")";
        itr++;
        if (itr != map_var.end())
            os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
template <typename T> ostream &operator<<(ostream &os, const set<T> &set_var) {
    os << "{";
    for (auto itr = set_var.begin(); itr != set_var.end(); itr++) {
        os << *itr;
        ++itr;
        if (itr != set_var.end())
            os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
#ifdef LOCAL
#define show(...) _show(0, #__VA_ARGS__, __VA_ARGS__)
#else
#define show(...) true
#endif
template <typename T> void _show(int i, T name) {
    cerr << '\n';
}
template <typename T1, typename T2, typename... T3>
void _show(int i, const T1 &a, const T2 &b, const T3 &...c) {
    for (; a[i] != ',' && a[i] != '\0'; i++)
        cerr << a[i];
    cerr << ":" << b << " ";
    _show(i + 1, a, c...);
}

#include <unistd.h>

namespace fastio {
static constexpr uint32_t SZ = 1 << 17;
char ibuf[SZ];
char obuf[SZ];
char out[100];
// pointer of ibuf, obuf


uint32_t pil = 0, pir = 0, por = 0;

struct Pre {
    char num[10000][4];
    constexpr Pre() : num() {
        for (int i = 0; i < 10000; i++) {
            int n = i;
            for (int j = 3; j >= 0; j--) {
                num[i][j] = n % 10 | '0';
                n /= 10;
            }
        }
    }
} constexpr pre;

inline void load() {
    memmove(ibuf, ibuf + pil, pir - pil);
    pir = pir - pil + fread(ibuf + pir - pil, 1, SZ - pir + pil, stdin);
    pil = 0;
    if (pir < SZ)
        ibuf[pir++] = '\n';
}

inline void flush() {
    fwrite(obuf, 1, por, stdout);
    por = 0;
}

void rd(char &c) {
    do {
        if (pil + 1 > pir)
            load();
        c = ibuf[pil++];
    } while (isspace(c));
}

void rd(string &x) {
    x.clear();
    char c;
    do {
        if (pil + 1 > pir)
            load();
        c = ibuf[pil++];
    } while (isspace(c));
    do {
        x += c;
        if (pil == pir)
            load();
        c = ibuf[pil++];
    } while (!isspace(c));
}

template <typename T> void rd_real(T &x) {
    string s;
    rd(s);
    x = stod(s);
}

template <typename T> void rd_integer(T &x) {
    if (pil + 100 > pir)
        load();
    char c;
    do
        c = ibuf[pil++];
    while (c < '-');
    bool minus = 0;
    if constexpr (is_signed<T>::value || is_same_v<T, i128>) {
        if (c == '-') {
            minus = 1, c = ibuf[pil++];
        }
    }
    x = 0;
    while ('0' <= c) {
        x = x * 10 + (c & 15), c = ibuf[pil++];
    }
    if constexpr (is_signed<T>::value || is_same_v<T, i128>) {
        if (minus)
            x = -x;
    }
}

void rd(int &x) {
    rd_integer(x);
}
void rd(ll &x) {
    rd_integer(x);
}
void rd(i128 &x) {
    rd_integer(x);
}
void rd(uint &x) {
    rd_integer(x);
}
void rd(ull &x) {
    rd_integer(x);
}
void rd(u128 &x) {
    rd_integer(x);
}
void rd(double &x) {
    rd_real(x);
}
void rd(long double &x) {
    rd_real(x);
}

template <class T, class U> void rd(pair<T, U> &p) {
    return rd(p.first), rd(p.second);
}
template <size_t N = 0, typename T> void rd_tuple(T &t) {
    if constexpr (N < std::tuple_size<T>::value) {
        auto &x = std::get<N>(t);
        rd(x);
        rd_tuple<N + 1>(t);
    }
}
template <class... T> void rd(tuple<T...> &tpl) {
    rd_tuple(tpl);
}

template <size_t N = 0, typename T> void rd(array<T, N> &x) {
    for (auto &d : x)
        rd(d);
}
template <class T> void rd(vector<T> &x) {
    for (auto &d : x)
        rd(d);
}

void read() {}
template <class H, class... T> void read(H &h, T &...t) {
    rd(h), read(t...);
}

void wt(const char c) {
    if (por == SZ)
        flush();
    obuf[por++] = c;
}
void wt(const string s) {
    for (char c : s)
        wt(c);
}
void wt(const char *s) {
    size_t len = strlen(s);
    for (size_t i = 0; i < len; i++)
        wt(s[i]);
}

template <typename T> void wt_integer(T x) {
    if (por > SZ - 100)
        flush();
    if (x < 0) {
        obuf[por++] = '-', x = -x;
    }
    int outi;
    for (outi = 96; x >= 10000; outi -= 4) {
        memcpy(out + outi, pre.num[x % 10000], 4);
        x /= 10000;
    }
    if (x >= 1000) {
        memcpy(obuf + por, pre.num[x], 4);
        por += 4;
    } else if (x >= 100) {
        memcpy(obuf + por, pre.num[x] + 1, 3);
        por += 3;
    } else if (x >= 10) {
        int q = (x * 103) >> 10;
        obuf[por] = q | '0';
        obuf[por + 1] = (x - q * 10) | '0';
        por += 2;
    } else
        obuf[por++] = x | '0';
    memcpy(obuf + por, out + outi + 4, 96 - outi);
    por += 96 - outi;
}

template <typename T> void wt_real(T x) {
    ostringstream oss;
    oss << fixed << setprecision(15) << double(x);
    string s = oss.str();
    wt(s);
}

void wt(int x) {
    wt_integer(x);
}
void wt(ll x) {
    wt_integer(x);
}
void wt(i128 x) {
    wt_integer(x);
}
void wt(uint x) {
    wt_integer(x);
}
void wt(ull x) {
    wt_integer(x);
}
void wt(u128 x) {
    wt_integer(x);
}
void wt(double x) {
    wt_real(x);
}
void wt(long double x) {
    wt_real(x);
}

template <class T, class U> void wt(const pair<T, U> val) {
    wt(val.first);
    wt(' ');
    wt(val.second);
}
template <size_t N = 0, typename T> void wt_tuple(const T t) {
    if constexpr (N < std::tuple_size<T>::value) {
        if constexpr (N > 0) {
            wt(' ');
        }
        const auto x = std::get<N>(t);
        wt(x);
        wt_tuple<N + 1>(t);
    }
}
template <class... T> void wt(tuple<T...> tpl) {
    wt_tuple(tpl);
}
template <class T, size_t S> void wt(const array<T, S> val) {
    auto n = val.size();
    for (size_t i = 0; i < n; i++) {
        if (i)
            wt(' ');
        wt(val[i]);
    }
}
template <class T> void wt(const vector<T> val) {
    auto n = val.size();
    for (size_t i = 0; i < n; i++) {
        if (i)
            wt(' ');
        wt(val[i]);
    }
}

void print() {
    wt('\n');
}
template <class Head, class... Tail> void print(Head &&head, Tail &&...tail) {
    wt(head);
    if (sizeof...(Tail))
        wt(' ');
    print(forward<Tail>(tail)...);
}
void __attribute__((destructor)) _d() {
    flush();
}
} // namespace fastio


using fastio::flush;
using fastio::print;
using fastio::read;

inline void first(bool i = true) {
    print(i ? "first" : "second");
}
inline void Alice(bool i = true) {
    print(i ? "Alice" : "Bob");
}
inline void Takahashi(bool i = true) {
    print(i ? "Takahashi" : "Aoki");
}
inline void yes(bool i = true) {
    print(i ? "yes" : "no");
}
inline void Yes(bool i = true) {
    print(i ? "Yes" : "No");
}
inline void No() {
    print("No");
}
inline void YES(bool i = true) {
    print(i ? "YES" : "NO");
}
inline void NO() {
    print("NO");
}
inline void Yay(bool i = true) {
    print(i ? "Yay!" : ":(");
}
inline void Possible(bool i = true) {
    print(i ? "Possible" : "Impossible");
}
inline void POSSIBLE(bool i = true) {
    print(i ? "POSSIBLE" : "IMPOSSIBLE");
}

/**
 * @brief Fast IO
 */

int A[4], N;
map<string,int> mp;
vector<vector<string>> S;
vector<string> C;

void DFS(int X) {
    rep(i,0,S[X].size()) {
        if (S[X][i][0] == '[') C.push_back(S[X][i]);
        else DFS(mp[S[X][i]]);
    }
}

int main() {
    cin >> A[0] >> A[1] >> A[2] >> A[3] >> N;
    S.resize(N);
    vector<string> U;
    string s;
    while(cin >> s) {
        U.push_back(s);
    }
    int Cur = -1;
    rep(i,0,U.size()) {
        if (U[i].back() == ':') {
            Cur++;
            mp[U[i].substr(0,U[i].size()-1)] = Cur;
        }
        else S[Cur].push_back(U[i]);
    }
    vector<ll> L(N,0);
    rrep(i,0,N) {
        rep(j,0,S[i].size()) {
            if (S[i][j][0] == '[') L[i]++;
            else L[i] += L[mp[S[i][j]]];
            chmin(L[i],(ll)inf);
        }
    }
    if (L[0] != A[0]+A[1]+A[2]+A[3]) {
        cout << 0 << endl;
        return 0;
    }
    static ll DP[51][51][51][51] = {};
    DP[0][0][0][0] = 1;
    DFS(0);
    rep(s,0,C.size()) {
        rep(i,0,51) {
            rep(j,0,51) {
                rep(k,0,51) {
                    int l = s-i-j-k;
                    if (l < 0) break;
                    DP[i][j][k][l] %= 1000000007;
                    string T = C[s];
                    rep(m,1,T.size()-1) {
                        if (T[m] == 'A' && i < 50) DP[i+1][j][k][l] += DP[i][j][k][l];
                        if (T[m] == 'T' && j < 50) DP[i][j+1][k][l] += DP[i][j][k][l];
                        if (T[m] == 'G' && k < 50) DP[i][j][k+1][l] += DP[i][j][k][l];
                        if (T[m] == 'C' && l < 50) DP[i][j][k][l+1] += DP[i][j][k][l];
                    }
                }
            }
        }
    }
    cout << DP[A[0]][A[1]][A[2]][A[3]] % 1000000007 << endl;
}
accuracy: 1
time_ms: 340
memory_kb: 56364
final_rank: 11

code_snippet: #line 2 "cp-library/src/cp-template.hpp"
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ld = long double;
using uint = unsigned int;
using ull  = unsigned long long;
using i32 = int;
using u32 = unsigned int;
using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128_t;
template < class T > bool chmin(T& a, T b) { if(a > b) { a = b; return true; } return false; }
template < class T > bool chmax(T& a, T b) { if(a < b) { a = b; return true; } return false; }
template < class T, class U > T ceil (T x, U y) { return (x > 0 ? (x + y - 1) / y :           x / y); }
template < class T, class U > T floor(T x, U y) { return (x > 0 ?           x / y : (x - y + 1) / y); }
int popcnt(i32 x) { return __builtin_popcount(x); }
int popcnt(u32 x) { return __builtin_popcount(x); }
int popcnt(i64 x) { return __builtin_popcountll(x); }
int popcnt(u64 x) { return __builtin_popcountll(x); }

#line 2 "cp-library/src/utility/rep_itr.hpp"
template < class T > struct itr_rep {
    T i, d;
    constexpr itr_rep(const T i) noexcept : i(i), d(1) {}
    constexpr itr_rep(const T i, const T d) noexcept : i(i), d(d) {}
    void operator++() noexcept { i += d; }
    constexpr int operator*() const noexcept { return i; }
    constexpr bool operator!=(const itr_rep x) const noexcept { return d > 0 ? i < x.i : i > x.i; }
};

template < class T > struct rep {
    const itr_rep< T > s, t;
    constexpr rep(const T t) noexcept : s(0), t(t) {}
    constexpr rep(const T s, const T t) noexcept : s(s), t(t) {}
    constexpr rep(const T s, const T t, const T d) noexcept : s(s, d), t(t, d) {}
    constexpr auto begin() const noexcept { return s; }
    constexpr auto end  () const noexcept { return t; }
};

template < class T > struct revrep {
    const itr_rep < T > s, t;
    constexpr revrep(const T t) noexcept : s(t - 1, -1), t(-1, -1) {}
    constexpr revrep(const T s, const T t) noexcept : s(t - 1, -1), t(s - 1, -1) {}
    constexpr revrep(const T s, const T t, const T d) noexcept : s(t - 1, -d), t(s - 1, -d) {}
    constexpr auto begin() const noexcept { return s; }
    constexpr auto end  () const noexcept { return t; }
};
#line 3 "cp-library/src/utility/io.hpp"

/* 128bit integer */
istream& operator>>(istream& is, i128& x) {
    std::string s; is >> s;
    int pm = (s[0] == '-');
    x = 0;
    for(int i : rep(pm, int(s.size()))) x = x * 10 + (s[i] - '0');
    if(pm) x *= -1;
    return is;
}
ostream& operator<<(ostream& os, const i128& x) {
    if(x == 0) return os << '0';
    i128 y = x;
    if(y < 0) { os << '-'; y *= -1; }
    std::vector<int> ny;
    while(y > 0) { ny.push_back(y % 10); y /= 10; }
    for(int i : revrep(ny.size())) os << ny[i];
    return os;
}

template < class S, class T > istream& operator>>(istream& is,       std::pair< S, T >& x) { is >> x.first        >> x.second; return is; }
template < class S, class T > ostream& operator<<(ostream& os, const std::pair< S, T >& x) { os << x.first << " " << x.second; return os; }

namespace scanner {
    struct sca {
        template < class T > operator T() {
            T s; std::cin >> s; return s;
        }
    };
    struct vec {
        int n;
        vec(int n) : n(n) {}
        template < class T > operator std::vector< T >() {
            std::vector< T > v(n);
            for(T& x : v) std::cin >> x;
            return v;
        }
    };
    struct mat {
        int h, w;
        mat(int h, int w) : h(h), w(w) {}
        template < class T > operator std::vector< std::vector< T > >() {
            std::vector m(h, std::vector< T >(w));
            for(std::vector< T >& v : m) for(T& x : v) std::cin >> x;
            return m;
        }
    };
    struct speedup {
        speedup() {
            std::cin.tie(0);
            std::ios::sync_with_stdio(0);
        }
    } speedup_instance;
}
scanner::sca in() { return scanner::sca(); }
scanner::vec in(int n) { return scanner::vec(n); }
scanner::mat in(int h, int w) { return scanner::mat(h, w); }

namespace printer {
    void precision(int d) { std::cout << std::fixed << std::setprecision(d); }
    void flush() { std::cout.flush(); }
}

template < class T >
ostream& operator<<(ostream& os, const std::vector< T > a) {
    int n = a.size();
    for(int i : rep(n)) { os << a[i]; if(i != n - 1) os << ' '; }
    return os;
}

int print() { std::cout << '\n'; return 0; }
template < class head, class... tail > int print(head&& h, tail&&... t) {
    std::cout << h; if(sizeof...(tail)) std::cout << ' ';
    return print(std::forward<tail>(t)...);
}
template < class T > int print_n(const std::vector< T > a) {
    int n = a.size();
    for(int i : rep(n)) std::cout << a[i] << "\n";
    return 0;
}


#line 2 "cp-library/src/utility/key_val.hpp"

template < class K, class V >
struct key_val {
    K key; V val;
    key_val() {}
    key_val(K key, V val) : key(key), val(val) {}
    template < std::size_t Index >
    std::tuple_element_t< Index, key_val >& get() {
        if constexpr (Index == 0) return key;
        if constexpr (Index == 1) return val;
    }
};

namespace std {

template < class K, class V > struct tuple_size < key_val< K, V > > : integral_constant< size_t, 2 > {};
template < class K, class V > struct tuple_element < 0, key_val< K, V > > { using type = K; };
template < class K, class V > struct tuple_element < 1, key_val< K, V > > { using type = V; };

}
#line 2 "cp-library/src/utility/vec_op.hpp"
template < class T > key_val< int, T > max_of(const vector< T >& a) {
    int i = std::max_element(a.begin(), a.end()) - a.begin();
    return {i, a[i]};
}
template < class T > key_val< int, T > min_of(const vector< T >& a) {
    int i = std::min_element(a.begin(), a.end()) - a.begin();
    return {i, a[i]};
}
template < class S, class T > S sum_of(const vector< T >& a) {
    S sum = 0;
    for(const T x : a) sum += x;
    return sum;
}
template < class S, class T > vector< S > freq_of(const vector< T >& a, T L, T R) {
    vector< S > res(R - L, S(0));
    for(const T x : a) res[x - L] += 1;
    return res;
}
template < class S, class T > struct prefix_sum {
    vector< S > s;
    prefix_sum(const vector< T >& a) : s(a) {
        s.insert(s.begin(), S(0));
        for(int i : rep(a.size())) s[i + 1] += s[i];
    }
    // [L, R)
    S sum(int L, int R) { return s[R] - s[L]; }
};
#line 3 "cp-library/src/utility/heap.hpp"

template < class T > using heap_min = std::priority_queue< T, std::vector< T >, std::greater< T > >;
template < class T > using heap_max = std::priority_queue< T, std::vector< T >, std::less< T > >;

#line 27 "cp-library/src/cp-template.hpp"

#line 1 "cp-library/src/algorithm/bin_search.hpp"
template < class T, class F >
T bin_search(T ok, T ng, F f) {
    while(abs(ng - ok) > 1) {
        T mid = (ok + ng) / 2;
        (f(mid) ? ok : ng) = mid;
    }
    return ok;
}

template < class T, class F >
T bin_search_real(T ok, T ng, F f, int step = 80) {
    while(step--) {
        T mid = (ok + ng) / 2;
        (f(mid) ? ok : ng) = mid;
    }
    return ok;
}
#line 2 "cp-library/src/algorithm/argsort.hpp"

template < class T > std::vector< int > argsort(const std::vector< T > &a) {
    std::vector< int > ids((int)a.size());
    std::iota(ids.begin(), ids.end(), 0);
    std::sort(ids.begin(), ids.end(), [&](int i, int j) {
        return a[i] < a[j] || (a[i] == a[j] && i < j);
    });
    return ids;
}
#line 1 "macro.hpp"
namespace macro {

using size_type = int;
template < class container > void  sort(container& a) { std::sort(std:: begin(a), std:: end(a)); }
template < class container > void rsort(container& a) { std::sort(std::rbegin(a), std::rend(a)); }
template < class container > void reverse(container& a) { std::reverse(std::begin(a), std::end(a)); }
template < class container > void unique(container& a) {
    std::sort(std::begin(a), std::end(a));
    a.erase(std::unique(std::begin(a), std::end(a)), std::end(a));
}
template < class container > container  sorted(const container& a) { container b = a;  sort(b); return std::move(b); }
template < class container > container rsorted(const container& a) { container b = a; rsort(b); return std::move(b); }
template < class container, class compare > void sort(container& a, const compare& cmp) { std::sort(std::begin(a), std::end(a), cmp); }
template < class container, class compare > container sorted(const container& a, const compare& cmp) { container b = a; sort(b, cmp); return std::move(b); }
template < class container, class value > size_type lower_bound(const container& a, const value& x) { return std::lower_bound(std::begin(a), std::end(a), x) - std::begin(a); }
template < class container, class value > size_type upper_bound(const container& a, const value& x) { return std::upper_bound(std::begin(a), std::end(a), x) - std::begin(a); }

const std::vector<std::pair<size_type, size_type>> dir4 = { {+1,  0}, {-1,  0}, { 0, +1}, { 0, -1} };
const std::vector<std::pair<size_type, size_type>> dir8 = { {-1, -1}, {-1,  0}, {-1, +1}, { 0, -1}, { 0, +1}, {+1, -1}, {+1,  0}, {+1, +1} };

#ifdef _DEBUG
#define debug(x) std::cout << "[" << __LINE__ << "] " << #x << ": " << x << std::endl
#else
#define debug(x)
#endif

template < class container > void concat(container& a, const container& b) {
    a.insert(std::end(a), std::begin(b), std::end(b));
}
std::vector<size_type> iota(const size_type n) {
    std::vector<size_type> I(n);
    std::iota(std::begin(I), std::end(I), 0);
    return I;
}
template < class container > std::vector<size_type> sort_idx(const container& a) {
    const size_type n = a.size();
    std::vector<size_type> I = iota(n);
    std::sort(std::begin(I), std::end(I), [&](size_type i, size_type j) { return a[i] < a[j] or (a[i] == a[j] and i < j); });
    return I;
}
template < class container, class compare > std::vector<size_type> sort_idx(const container& a, const compare& cmp) {
    const size_type n = a.size();
    std::vector<size_type> I = iota(n);
    std::sort(std::begin(I), std::end(I), [&](size_type i, size_type j) { return cmp(a[i], a[j]) or (a[i] == a[j] and i < j); });
    return std::move(I);
}

struct grid {
    using size_type = int;
    size_type H, W;
    grid(const size_type H, const size_type W) : H(H), W(W) {}
    bool contains(const size_type i, const size_type j) {
        return 0 <= i and i < H and 0 <= j and j < W;
    }
};

using f64 = long double;

} // namespace macro

using namespace macro;
#line 3 "A.cpp"

int main() {
    int Na = in(), Nt = in(), Ng = in(), Nc = in();
    int m = in();
    map<string, vector<string>> mp;
    string key0 = "";
    cin.ignore();
    for(int _ : rep(m)) {
        string s; getline(cin, s);
        int mid = find(s.begin(), s.end(), ':') - s.begin();
        string key = s.substr(0, mid);
        if(_ == 0) key0 = key;
        string t = s.substr(mid + 1);
        vector<int> I;
        for(int i : rep(int(t.size()))) if(t[i] == ' ') I.push_back(i);
        I.push_back(t.size());
        vector<string> value;
        for(int i : rep(int(I.size()) - 1)) {
            string u = t.substr(I[i] + 1, I[i + 1] - (I[i] + 1));
            value.push_back(u);
        }
        mp[key] = value;
    }

    const int len = Na + Nt + Ng + Nc;

    auto dfs = [&](auto self, string key) -> vector<string> {
        vector<string> value = mp[key];
        vector<string> res;
        for(string v : value) {
            if(v[0] == '[') {
                res.push_back(v);
            } else {
                vector<string> v2 = self(self, v);
                res.insert(res.end(), v2.begin(), v2.end());
            }
            if(len < res.size()) exit(print(0));
        }
        return res;
    };

    vector<string> value = dfs(dfs, key0);
    if(value.size() != len) return print(0);
    const i64 MOD = 1e9+7;
    vector dp(Na + 1, vector(Nt + 1, vector(Ng + 1, i64(0))));
    dp[0][0][0] = 1;
    for(int i : rep(len)) {
        vector nt(Na + 1, vector(Nt + 1, vector(Ng + 1, i64(0))));
        for(char c : value[i]) if(isalpha(c)) {
            for(int a = 0; a <= Na; a++) {
                for(int t = 0; t <= Nt; t++) {
                    for(int g = 0; g <= Ng; g++) {
                        if(c == 'A' and a + 1 <= Na) { nt[a + 1][t][g] += dp[a][t][g]; nt[a + 1][t][g] %= MOD; }
                        if(c == 'T' and t + 1 <= Nt) { nt[a][t + 1][g] += dp[a][t][g]; nt[a][t + 1][g] %= MOD; }
                        if(c == 'G' and g + 1 <= Ng) { nt[a][t][g + 1] += dp[a][t][g]; nt[a][t][g + 1] %= MOD; }
                        if(c == 'C') { nt[a][t][g] += dp[a][t][g]; nt[a][t][g] %= MOD; }
                    }
                }
            }
        }
        dp = move(nt);
    }

    print(dp[Na][Nt][Ng]);
}
accuracy: 1
time_ms: 170
memory_kb: 5128
final_rank: 2

code_snippet: #include <bits/stdc++.h>

constexpr int MOD = 1000000007;

struct LengthError {};

struct State {
    using ATGC = std::array<int, 4>;
    std::map<ATGC, int> mp;
    State() {}
    State(int a, int t, int g, int c) {
        ATGC tu = {a, t, g, c};
        mp[tu] = 1;
    }

    void progress(std::string s) {
        std::vector<int> index;
        for (auto c: s) {
            if (c == 'A') index.push_back(0);
            if (c == 'T') index.push_back(1);
            if (c == 'G') index.push_back(2);
            if (c == 'C') index.push_back(3);
        }
        std::map<ATGC, int> next;
        for (const auto& [atgc, val]: mp) {
            for (auto i: index) {
                if (atgc[i] > 0) {
                    auto next_atgc = atgc;
                    next_atgc[i]--;
                    auto& next_val = next[next_atgc];
                    next_val += val;
                    if (next_val > MOD) {
                        next_val -= MOD;
                    }
                }
            }
        }
        if (next.empty()) {
            throw LengthError();
        }
        mp = std::move(next);
    }
};

struct Parser {
    std::vector<std::string> lines;
    std::map<std::string, int> name_to_index;

    Parser(const std::vector<std::string>& s) {
        for (int i = 0; i < (int)s.size(); i++) {
            int pos = s[i].find(':');
            auto name = s[i].substr(0, pos);
            auto line = s[i].substr(pos + 2);
            name_to_index[name] = i;
            lines.push_back(line);
        }
    }

    State state;
    int parse(int a, int t, int g, int c) {
        state = State(a, t, g, c);
        try {
            match(0);
            if (state.mp.size() != 1) {
                return 0;
            }
            if (state.mp.find({0, 0, 0, 0}) == state.mp.end()) {
                return 0;
            }
            return state.mp[{0, 0, 0, 0}];
        } catch(LengthError) {
            return 0;
        }
    }

    using Iter = std::string::const_iterator&;

    void skip(Iter it, char c) {
        assert(*it == c);
        ++it;
    }

    void match(int id) {
        auto it = lines[id].cbegin();
        while (it != lines[id].end()) {
            if (*it == '[') {
                skip(it, '[');
                std::string res;
                while (it != lines[id].end() && std::isalpha(*it)) {
                    res.push_back(*it);
                    ++it;
                }
                skip(it, ']');
                state.progress(res);
            } else {
                std::string name;
                while (it != lines[id].end() && std::isalpha(*it)) {
                    name.push_back(*it);
                    ++it;
                }
                int nid = name_to_index[name];
                match(nid);
            }
            if (it != lines[id].end()) skip(it, ' ');
        }
    }
};

int main() {
    int a, t, g, c;
    std::cin >> a >> t >> g >> c;
    int m;
    std::cin >> m;
    std::cin.ignore();
    std::vector<std::string> lines(m);
    for (int i = 0; i < m; i++) {
        std::getline(std::cin, lines[i]);
    }

    Parser parser(lines);
    std::cout << parser.parse(a, t, g, c) << std::endl;
}
accuracy: 1
time_ms: 1420
memory_kb: 13096
final_rank: 14

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = int;
using vll = vector<ll>;
using vvll = vector<vll>;
using vvvll = vector<vvll>;
using vvvvll = vector<vvvll>;
using vvvvvll = vector<vvvvll>;
using vb = vector<bool>;
using vvb = vector<vb>;
using vvvb = vector<vvb>;
using vd = vector<double>;
using vvd = vector<vd>;
using vvvd = vector<vvd>;
#define all(A) A.begin(),A.end()
#define ALL(A) A.begin(),A.end()
#define rep(i, n) for (ll i = 0; i < (ll) (n); i++)
using pqr = priority_queue<pair<ll, ll>, vector<pair<ll, ll>>, greater<pair<ll, ll>>>;

template<class T>
bool chmax(T& p, T q, bool C = 1) {
    if (C == 0 && p == q) {
        return 1;
    }
    if (p < q) {
        p = q;
        return 1;
    }
    else {
        return 0;
    }
}

template<class T>
bool chmin(T& p, T q, bool C = 1) {
    if (C == 0 && p == q) {
        return 1;
    }
    if (p > q) {
        p = q;
        return 1;
    }
    else {
        return 0;
    }
}

ll gcd(ll(a), ll(b)) {
    if (b == 0)return a;
    ll c = a;
    while (a % b != 0) {
        c = a % b;
        a = b;
        b = c;
    }
    return b;
}

vector<ll> fact, factinv, inv;
ll mod = 1e9 + 7;
void prenCkModp(ll n) {
    fact.resize(n + 5);
    factinv.resize(n + 5);
    inv.resize(n + 5);
    fact.at(0) = fact.at(1) = 1;
    factinv.at(0) = factinv.at(1) = 1;
    inv.at(1) = 1;
    for (ll i = 2; i < n + 5; i++) {
        fact.at(i) = (fact.at(i - 1) * i) % mod;
        inv.at(i) = mod - (inv.at(mod % i) * (mod / i)) % mod;
        factinv.at(i) = (factinv.at(i - 1) * inv.at(i)) % mod;
    }

}
ll nCk(ll n, ll k) {
    if (k < 0)return 0;
    if (n < k) return 0;
    return fact.at(n) * (factinv.at(k) * factinv.at(n - k) % mod) % mod;
}


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

    ll A, T, G, C;
    cin >> A >> T >> G >> C;
    ll N = A + T + G + C;
    ll M;
    cin >> M;
    vector<string> V(M);
    string S;
    getline(cin, S);
    rep(m, M) {
     
        getline(cin, S);
        V[M - m - 1] = S;
    }
    map<string, vector<string>> DNA;
    string num;
    rep(m, M) {
        ll L = 0;
        
        vector<string> res;
        rep(j, V[m].size()) {
            if (V[m][j] == ' ') {
                if (L != 0) {
                    string AT = V[m].substr(L + 1, j-L-1);
                    if (AT[0] != '[') {
                        res.insert(res.end(), all(DNA[AT]));
                    }
                    else {
                        res.push_back(AT.substr(1,j-L-3));
                    }
                    L = j;
                }
                else {
                    num = V[m].substr(0, j-1);
                    L = j;
                }
            }
            
        }
        ll j = V[m].size();
        string AT = V[m].substr(L + 1, j - 1);
        if (AT[0] != '[') {
            res.insert(res.end(), all(DNA[AT]));
        }
        else {
            res.push_back(AT.substr(1,j-L-3));
        }
        L = j;
        if (res.size() > 200) {
            cout << 0 << endl;
            return 0;
        }
        DNA[num] = res;
    }

    vvvll DP(A + 1, vvll(T + 1, vll(G + 1, 0)));
    vector<string> DS = DNA[num];
    if (DS.size() != N) {
        cout << 0 << endl;
        return 0;
    }
    DP[0][0][0] = 1;
    ll mod = 1e9 + 7;
    rep(i, N) {
        vvvll NDP(A + 1, vvll(T + 1, vll(G + 1,0)));
        rep(a, A + 1) {
            rep(t, T + 1) {
                rep(g, G + 1) {
                        rep(p, DS[i].size()) {
                            if (DS[i][p] == 'A') {
                                if (a != A)NDP[a + 1][t][g] += DP[a][t][g];
                                if (a != A)NDP[a + 1][t][g] %= mod;
                            }
                            if (DS[i][p] == 'T') {
                                if (t != T)NDP[a][t+1][g] += DP[a][t][g];
                                if (t != T)NDP[a][t+1][g] %= mod;
                            }
                            if (DS[i][p] == 'G') {
                                if (g != G)NDP[a][t][g + 1] += DP[a][t][g];
                                if (g != G)NDP[a][t][g + 1] %= mod;
                            }
                            if (DS[i][p] == 'C') {
                                NDP[a][t][g] += DP[a][t][g];
                                NDP[a][t][g] %= mod;
                            }
                        
                    }
                }
            }
        }
        DP = NDP;
    }
    cout << DP[A][T][G] << endl;
}
accuracy: 1
time_ms: 210
memory_kb: 4312
final_rank: 4

code_snippet: #include <bits/stdc++.h>
using namespace std;
#ifdef tabr
#include "library/debug.cpp"
#else
#define debug(...)
#endif

template <long long mod>
struct modular {
    long long value;
    modular(long long x = 0) {
        value = x % mod;
        if (value < 0) value += mod;
    }
    modular& operator+=(const modular& other) {
        if ((value += other.value) >= mod) value -= mod;
        return *this;
    }
    modular& operator-=(const modular& other) {
        if ((value -= other.value) < 0) value += mod;
        return *this;
    }
    modular& operator*=(const modular& other) {
        value = value * other.value % mod;
        return *this;
    }
    modular& operator/=(const modular& other) {
        long long a = 0, b = 1, c = other.value, m = mod;
        while (c != 0) {
            long long t = m / c;
            m -= t * c;
            swap(c, m);
            a -= t * b;
            swap(a, b);
        }
        a %= mod;
        if (a < 0) a += mod;
        value = value * a % mod;
        return *this;
    }
    friend modular operator+(const modular& lhs, const modular& rhs) { return modular(lhs) += rhs; }
    friend modular operator-(const modular& lhs, const modular& rhs) { return modular(lhs) -= rhs; }
    friend modular operator*(const modular& lhs, const modular& rhs) { return modular(lhs) *= rhs; }
    friend modular operator/(const modular& lhs, const modular& rhs) { return modular(lhs) /= rhs; }
    modular& operator++() { return *this += 1; }
    modular& operator--() { return *this -= 1; }
    modular operator++(int) {
        modular res(*this);
        *this += 1;
        return res;
    }
    modular operator--(int) {
        modular res(*this);
        *this -= 1;
        return res;
    }
    modular operator-() const { return modular(-value); }
    bool operator==(const modular& rhs) const { return value == rhs.value; }
    bool operator!=(const modular& rhs) const { return value != rhs.value; }
    bool operator<(const modular& rhs) const { return value < rhs.value; }
};
template <long long mod>
string to_string(const modular<mod>& x) {
    return to_string(x.value);
}
template <long long mod>
ostream& operator<<(ostream& stream, const modular<mod>& x) {
    return stream << x.value;
}
template <long long mod>
istream& operator>>(istream& stream, modular<mod>& x) {
    stream >> x.value;
    x.value %= mod;
    if (x.value < 0) x.value += mod;
    return stream;
}

constexpr long long mod = (int) 1e9 + 7;
using mint = modular<mod>;

mint power(mint a, long long n) {
    mint res = 1;
    while (n > 0) {
        if (n & 1) {
            res *= a;
        }
        a *= a;
        n >>= 1;
    }
    return res;
}

vector<mint> fact(1, 1);
vector<mint> finv(1, 1);

mint C(int n, int k) {
    if (n < k || k < 0) {
        return mint(0);
    }
    while ((int) fact.size() < n + 1) {
        fact.emplace_back(fact.back() * (int) fact.size());
        finv.emplace_back(mint(1) / fact.back());
    }
    return fact[n] * finv[k] * finv[n - k];
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    vector<int> c(4);
    for (int i = 0; i < 4; i++) {
        cin >> c[i];
    }
    int m;
    cin >> m;
    vector<string> s;
    string t;
    while (cin >> t) {
        s.emplace_back(t);
    }
    vector<vector<int>> a(m, vector<int>(16));
    map<string, int> mp;
    const string dna = "ATGC";
    auto Get = [&](string w) {
        int res = 0;
        for (char x : w) {
            for (int i = 0; i < 4; i++) {
                if (x == dna[i]) {
                    res |= 1 << i;
                }
            }
        }
        return res;
    };
    for (int i = m - 1; i >= 0; i--) {
        while (s.back().back() != ':') {
            if (s.back().back() == ']') {
                s.back().pop_back();
                s.back().erase(s.back().begin());
                a[i][Get(s.back())]++;
            } else {
                for (int j = 0; j < 16; j++) {
                    a[i][j] += a[mp[s.back()]][j];
                }
            }
            s.pop_back();
        }
        s.back().pop_back();
        mp[s.back()] = i;
        s.pop_back();
    }
    if (*min_element(a[0].begin(), a[0].end()) >= 0 && accumulate(a[0].begin(), a[0].end(), 0) != accumulate(c.begin(), c.end(), 0)) {
        cout << 0 << '\n';
        return 0;
    }
    vector<int> b;
    for (int i = 0; i < 16; i++) {
        for (int j = 0; j < a[0][i]; j++) {
            b.emplace_back(i);
        }
    }
    mint dp[52][52][52][52] = {};
    dp[0][0][0][0] = 1;
    int sum = 0;
    for (int x : b) {
        for (int i1 = 50; i1 >= 0; i1--) {
            for (int i2 = 50; i2 >= 0; i2--) {
                for (int i3 = 50; i3 >= 0; i3--) {
                    int i4 = sum - i1 - i2 - i3;
                    if (i4 < 0 || i4 > 50) {
                        continue;
                    }
                    for (int i = 0; i < 4; i++) {
                        if (~x & (1 << i)) {
                            continue;
                        }
                        auto [ni1, ni2, ni3, ni4] = make_tuple(i1, i2, i3, i4);
                        if (i == 0) {
                            ni1++;
                        } else if (i == 1) {
                            ni2++;
                        } else if (i == 2) {
                            ni3++;
                        } else {
                            ni4++;
                        }
                        dp[ni1][ni2][ni3][ni4] += dp[i1][i2][i3][i4];
                    }
                    dp[i1][i2][i3][i4] = 0;
                }
            }
        }
        sum++;
    }
    cout << dp[c[0]][c[1]][c[2]][c[3]] << '\n';
    return 0;
}
accuracy: 1
time_ms: 130
memory_kb: 60588
final_rank: 8

code_snippet: #include <bits/stdc++.h>
using namespace std;
#ifdef tabr
#include "library/debug.cpp"
#else
#define debug(...)
#endif

template <long long mod>
struct modular {
    long long value;
    modular(long long x = 0) {
        value = x % mod;
        if (value < 0) value += mod;
    }
    modular& operator+=(const modular& other) {
        if ((value += other.value) >= mod) value -= mod;
        return *this;
    }
    modular& operator-=(const modular& other) {
        if ((value -= other.value) < 0) value += mod;
        return *this;
    }
    modular& operator*=(const modular& other) {
        value = value * other.value % mod;
        return *this;
    }
    modular& operator/=(const modular& other) {
        long long a = 0, b = 1, c = other.value, m = mod;
        while (c != 0) {
            long long t = m / c;
            m -= t * c;
            swap(c, m);
            a -= t * b;
            swap(a, b);
        }
        a %= mod;
        if (a < 0) a += mod;
        value = value * a % mod;
        return *this;
    }
    friend modular operator+(const modular& lhs, const modular& rhs) { return modular(lhs) += rhs; }
    friend modular operator-(const modular& lhs, const modular& rhs) { return modular(lhs) -= rhs; }
    friend modular operator*(const modular& lhs, const modular& rhs) { return modular(lhs) *= rhs; }
    friend modular operator/(const modular& lhs, const modular& rhs) { return modular(lhs) /= rhs; }
    modular& operator++() { return *this += 1; }
    modular& operator--() { return *this -= 1; }
    modular operator++(int) {
        modular res(*this);
        *this += 1;
        return res;
    }
    modular operator--(int) {
        modular res(*this);
        *this -= 1;
        return res;
    }
    modular operator-() const { return modular(-value); }
    bool operator==(const modular& rhs) const { return value == rhs.value; }
    bool operator!=(const modular& rhs) const { return value != rhs.value; }
    bool operator<(const modular& rhs) const { return value < rhs.value; }
};
template <long long mod>
string to_string(const modular<mod>& x) {
    return to_string(x.value);
}
template <long long mod>
ostream& operator<<(ostream& stream, const modular<mod>& x) {
    return stream << x.value;
}
template <long long mod>
istream& operator>>(istream& stream, modular<mod>& x) {
    stream >> x.value;
    x.value %= mod;
    if (x.value < 0) x.value += mod;
    return stream;
}

constexpr long long mod = (int) 1e9 + 7;
using mint = modular<mod>;

mint power(mint a, long long n) {
    mint res = 1;
    while (n > 0) {
        if (n & 1) {
            res *= a;
        }
        a *= a;
        n >>= 1;
    }
    return res;
}

vector<mint> fact(1, 1);
vector<mint> finv(1, 1);

mint C(int n, int k) {
    if (n < k || k < 0) {
        return mint(0);
    }
    while ((int) fact.size() < n + 1) {
        fact.emplace_back(fact.back() * (int) fact.size());
        finv.emplace_back(mint(1) / fact.back());
    }
    return fact[n] * finv[k] * finv[n - k];
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    vector<int> c(4);
    for (int i = 0; i < 4; i++) {
        cin >> c[i];
    }
    int m;
    cin >> m;
    vector<string> s;
    string t;
    while (cin >> t) {
        s.emplace_back(t);
    }
    vector<vector<int>> a(m, vector<int>(16));
    map<string, int> mp;
    const string dna = "ATGC";
    auto Get = [&](string w) {
        int res = 0;
        for (char x : w) {
            for (int i = 0; i < 4; i++) {
                if (x == dna[i]) {
                    res |= 1 << i;
                }
            }
        }
        return res;
    };
    for (int i = m - 1; i >= 0; i--) {
        while (s.back().back() != ':') {
            if (s.back().back() == ']') {
                s.back().pop_back();
                s.back().erase(s.back().begin());
                a[i][Get(s.back())]++;
            } else {
                for (int j = 0; j < 16; j++) {
                    a[i][j] += a[mp[s.back()]][j];
                }
            }
            s.pop_back();
        }
        s.back().pop_back();
        mp[s.back()] = i;
        s.pop_back();
    }
    if (*min_element(a[0].begin(), a[0].end()) >= 0 && accumulate(a[0].begin(), a[0].end(), 0) != accumulate(c.begin(), c.end(), 0)) {
        cout << 0 << '\n';
        return 0;
    }
    vector<int> b;
    for (int i = 0; i < 16; i++) {
        for (int j = 0; j < a[0][i]; j++) {
            b.emplace_back(i);
        }
    }
    mint dp[52][52][52][52] = {};
    dp[0][0][0][0] = 1;
    for (int x : b) {
        for (int i1 = 50; i1 >= 0; i1--) {
            for (int i2 = 50; i2 >= 0; i2--) {
                for (int i3 = 50; i3 >= 0; i3--) {
                    for (int i4 = 50; i4 >= 0; i4--) {
                        for (int i = 0; i < 4; i++) {
                            if (~x & (1 << i)) {
                                continue;
                            }
                            auto [ni1, ni2, ni3, ni4] = make_tuple(i1, i2, i3, i4);
                            if (i == 0) {
                                ni1++;
                            } else if (i == 1) {
                                ni2++;
                            } else if (i == 2) {
                                ni3++;
                            } else {
                                ni4++;
                            }
                            dp[ni1][ni2][ni3][ni4] += dp[i1][i2][i3][i4];
                            dp[i1][i2][i3][i4] = 0;
                        }
                    }
                }
            }
        }
    }
    cout << dp[c[0]][c[1]][c[2]][c[3]] << '\n';
    return 0;
}
accuracy: 0.023255813953488372
time_ms: 160
memory_kb: 60436
final_rank: 20

code_snippet: #line 2 "library/bits/stdc++.h"

// C
#ifndef _GLIBCXX_NO_ASSERT
#include <cassert>
#endif
#include <cctype>
#include <cerrno>
#include <cfloat>
#include <ciso646>
#include <climits>
#include <clocale>
#include <cmath>
#include <csetjmp>
#include <csignal>
#include <cstdarg>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>

#if __cplusplus >= 201103L
#include <ccomplex>
#include <cfenv>
#include <cinttypes>
#include <cstdbool>
#include <cstdint>
#include <ctgmath>
#include <cwchar>
#include <cwctype>
#endif

// C++
#include <algorithm>
#include <bitset>
#include <complex>
#include <deque>
#include <exception>
#include <fstream>
#include <functional>
#include <iomanip>
#include <ios>
#include <iosfwd>
#include <iostream>
#include <istream>
#include <iterator>
#include <limits>
#include <list>
#include <locale>
#include <map>
#include <memory>
#include <new>
#include <numeric>
#include <ostream>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <stdexcept>
#include <streambuf>
#include <string>
#include <typeinfo>
#include <utility>
#include <valarray>
#include <vector>

#if __cplusplus >= 201103L
#include <array>
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <forward_list>
#include <future>
#include <initializer_list>
#include <mutex>
#include <random>
#include <ratio>
#include <regex>
#include <scoped_allocator>
#include <system_error>
#include <thread>
#include <tuple>
#include <typeindex>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#endif
#line 2 "Source.cpp"
using namespace std;

typedef string::const_iterator State;
#define eps 1e-8L
#define MAX_MOD 1000000007LL
#define GYAKU 500000004LL
#define MOD 998244353LL
#define pb push_back
#define mp make_pair
typedef long long ll;
typedef long double ld;
#define REP(a, b) for (long long(a) = 0; (a) < (b); ++(a))
#define ALL(x) (x).begin(), (x).end()

#line 1 "library/atcoder/modint.hpp"



#include <cassert>
#line 6 "library/atcoder/modint.hpp"
#include <type_traits>

#ifdef _MSC_VER
#include <intrin.h>
#endif

#line 1 "library/atcoder/internal_math.hpp"



#line 5 "library/atcoder/internal_math.hpp"

#ifdef _MSC_VER
#include <intrin.h>
#endif

namespace atcoder {

namespace internal {

// @param m `1 <= m`
// @return x mod m
constexpr long long safe_mod(long long x, long long m) {
    x %= m;
    if (x < 0) x += m;
    return x;
}

// Fast modular multiplication by barrett reduction
// Reference: https://en.wikipedia.org/wiki/Barrett_reduction
// NOTE: reconsider after Ice Lake
struct barrett {
    unsigned int _m;
    unsigned long long im;

    // @param m `1 <= m < 2^31`
    explicit barrett(unsigned int m) : _m(m), im((unsigned long long)(-1) / m + 1) {}

    // @return m
    unsigned int umod() const { return _m; }

    // @param a `0 <= a < m`
    // @param b `0 <= b < m`
    // @return `a * b % m`
    unsigned int mul(unsigned int a, unsigned int b) const {
        // [1] m = 1
        // a = b = im = 0, so okay

        // [2] m >= 2
        // im = ceil(2^64 / m)
        // -> im * m = 2^64 + r (0 <= r < m)
        // let z = a*b = c*m + d (0 <= c, d < m)
        // a*b * im = (c*m + d) * im = c*(im*m) + d*im = c*2^64 + c*r + d*im
        // c*r + d*im < m * m + m * im < m * m + 2^64 + m <= 2^64 + m * (m + 1) < 2^64 * 2
        // ((ab * im) >> 64) == c or c + 1
        unsigned long long z = a;
        z *= b;
#ifdef _MSC_VER
        unsigned long long x;
        _umul128(z, im, &x);
#else
        unsigned long long x =
            (unsigned long long)(((unsigned __int128)(z)*im) >> 64);
#endif
        unsigned int v = (unsigned int)(z - x * _m);
        if (_m <= v) v += _m;
        return v;
    }
};

// @param n `0 <= n`
// @param m `1 <= m`
// @return `(x ** n) % m`
constexpr long long pow_mod_constexpr(long long x, long long n, int m) {
    if (m == 1) return 0;
    unsigned int _m = (unsigned int)(m);
    unsigned long long r = 1;
    unsigned long long y = safe_mod(x, m);
    while (n) {
        if (n & 1) r = (r * y) % _m;
        y = (y * y) % _m;
        n >>= 1;
    }
    return r;
}

// Reference:
// M. Forisek and J. Jancina,
// Fast Primality Testing for Integers That Fit into a Machine Word
// @param n `0 <= n`
constexpr bool is_prime_constexpr(int n) {
    if (n <= 1) return false;
    if (n == 2 || n == 7 || n == 61) return true;
    if (n % 2 == 0) return false;
    long long d = n - 1;
    while (d % 2 == 0) d /= 2;
    constexpr long long bases[3] = {2, 7, 61};
    for (long long a : bases) {
        long long t = d;
        long long y = pow_mod_constexpr(a, t, n);
        while (t != n - 1 && y != 1 && y != n - 1) {
            y = y * y % n;
            t <<= 1;
        }
        if (y != n - 1 && t % 2 == 0) {
            return false;
        }
    }
    return true;
}
template <int n> constexpr bool is_prime = is_prime_constexpr(n);

// @param b `1 <= b`
// @return pair(g, x) s.t. g = gcd(a, b), xa = g (mod b), 0 <= x < b/g
constexpr std::pair<long long, long long> inv_gcd(long long a, long long b) {
    a = safe_mod(a, b);
    if (a == 0) return {b, 0};

    // Contracts:
    // [1] s - m0 * a = 0 (mod b)
    // [2] t - m1 * a = 0 (mod b)
    // [3] s * |m1| + t * |m0| <= b
    long long s = b, t = a;
    long long m0 = 0, m1 = 1;

    while (t) {
        long long u = s / t;
        s -= t * u;
        m0 -= m1 * u;  // |m1 * u| <= |m1| * s <= b

        // [3]:
        // (s - t * u) * |m1| + t * |m0 - m1 * u|
        // <= s * |m1| - t * u * |m1| + t * (|m0| + |m1| * u)
        // = s * |m1| + t * |m0| <= b

        auto tmp = s;
        s = t;
        t = tmp;
        tmp = m0;
        m0 = m1;
        m1 = tmp;
    }
    // by [3]: |m0| <= b/g
    // by g != b: |m0| < b/g
    if (m0 < 0) m0 += b / s;
    return {s, m0};
}

// Compile time primitive root
// @param m must be prime
// @return primitive root (and minimum in now)
constexpr int primitive_root_constexpr(int m) {
    if (m == 2) return 1;
    if (m == 167772161) return 3;
    if (m == 469762049) return 3;
    if (m == 754974721) return 11;
    if (m == 998244353) return 3;
    int divs[20] = {};
    divs[0] = 2;
    int cnt = 1;
    int x = (m - 1) / 2;
    while (x % 2 == 0) x /= 2;
    for (int i = 3; (long long)(i)*i <= x; i += 2) {
        if (x % i == 0) {
            divs[cnt++] = i;
            while (x % i == 0) {
                x /= i;
            }
        }
    }
    if (x > 1) {
        divs[cnt++] = x;
    }
    for (int g = 2;; g++) {
        bool ok = true;
        for (int i = 0; i < cnt; i++) {
            if (pow_mod_constexpr(g, (m - 1) / divs[i], m) == 1) {
                ok = false;
                break;
            }
        }
        if (ok) return g;
    }
}
template <int m> constexpr int primitive_root = primitive_root_constexpr(m);

// @param n `n < 2^32`
// @param m `1 <= m < 2^32`
// @return sum_{i=0}^{n-1} floor((ai + b) / m) (mod 2^64)
unsigned long long floor_sum_unsigned(unsigned long long n,
                                      unsigned long long m,
                                      unsigned long long a,
                                      unsigned long long b) {
    unsigned long long ans = 0;
    while (true) {
        if (a >= m) {
            ans += n * (n - 1) / 2 * (a / m);
            a %= m;
        }
        if (b >= m) {
            ans += n * (b / m);
            b %= m;
        }

        unsigned long long y_max = a * n + b;
        if (y_max < m) break;
        // y_max < m * (n + 1)
        // floor(y_max / m) <= n
        n = (unsigned long long)(y_max / m);
        b = (unsigned long long)(y_max % m);
        std::swap(m, a);
    }
    return ans;
}

}  // namespace internal

}  // namespace atcoder


#line 1 "library/atcoder/internal_type_traits.hpp"



#line 7 "library/atcoder/internal_type_traits.hpp"

namespace atcoder {

namespace internal {

#ifndef _MSC_VER
template <class T>
using is_signed_int128 =
    typename std::conditional<std::is_same<T, __int128_t>::value ||
                                  std::is_same<T, __int128>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using is_unsigned_int128 =
    typename std::conditional<std::is_same<T, __uint128_t>::value ||
                                  std::is_same<T, unsigned __int128>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using make_unsigned_int128 =
    typename std::conditional<std::is_same<T, __int128_t>::value,
                              __uint128_t,
                              unsigned __int128>;

template <class T>
using is_integral = typename std::conditional<std::is_integral<T>::value ||
                                                  is_signed_int128<T>::value ||
                                                  is_unsigned_int128<T>::value,
                                              std::true_type,
                                              std::false_type>::type;

template <class T>
using is_signed_int = typename std::conditional<(is_integral<T>::value &&
                                                 std::is_signed<T>::value) ||
                                                    is_signed_int128<T>::value,
                                                std::true_type,
                                                std::false_type>::type;

template <class T>
using is_unsigned_int =
    typename std::conditional<(is_integral<T>::value &&
                               std::is_unsigned<T>::value) ||
                                  is_unsigned_int128<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<
    is_signed_int128<T>::value,
    make_unsigned_int128<T>,
    typename std::conditional<std::is_signed<T>::value,
                              std::make_unsigned<T>,
                              std::common_type<T>>::type>::type;

#else

template <class T> using is_integral = typename std::is_integral<T>;

template <class T>
using is_signed_int =
    typename std::conditional<is_integral<T>::value && std::is_signed<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using is_unsigned_int =
    typename std::conditional<is_integral<T>::value &&
                                  std::is_unsigned<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<is_signed_int<T>::value,
                                              std::make_unsigned<T>,
                                              std::common_type<T>>::type;

#endif

template <class T>
using is_signed_int_t = std::enable_if_t<is_signed_int<T>::value>;

template <class T>
using is_unsigned_int_t = std::enable_if_t<is_unsigned_int<T>::value>;

template <class T> using to_unsigned_t = typename to_unsigned<T>::type;

}  // namespace internal

}  // namespace atcoder


#line 14 "library/atcoder/modint.hpp"

namespace atcoder {

namespace internal {

struct modint_base {};
struct static_modint_base : modint_base {};

template <class T> using is_modint = std::is_base_of<modint_base, T>;
template <class T> using is_modint_t = std::enable_if_t<is_modint<T>::value>;

}  // namespace internal

template <int m, std::enable_if_t<(1 <= m)>* = nullptr>
struct static_modint : internal::static_modint_base {
    using mint = static_modint;

  public:
    static constexpr int mod() { return m; }
    static mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }

    static_modint() : _v(0) {}
    template <class T, internal::is_signed_int_t<T>* = nullptr>
    static_modint(T v) {
        long long x = (long long)(v % (long long)(umod()));
        if (x < 0) x += umod();
        _v = (unsigned int)(x);
    }
    template <class T, internal::is_unsigned_int_t<T>* = nullptr>
    static_modint(T v) {
        _v = (unsigned int)(v % umod());
    }

    unsigned int val() const { return _v; }

    mint& operator++() {
        _v++;
        if (_v == umod()) _v = 0;
        return *this;
    }
    mint& operator--() {
        if (_v == 0) _v = umod();
        _v--;
        return *this;
    }
    mint operator++(int) {
        mint result = *this;
        ++*this;
        return result;
    }
    mint operator--(int) {
        mint result = *this;
        --*this;
        return result;
    }

    mint& operator+=(const mint& rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator-=(const mint& rhs) {
        _v -= rhs._v;
        if (_v >= umod()) _v += umod();
        return *this;
    }
    mint& operator*=(const mint& rhs) {
        unsigned long long z = _v;
        z *= rhs._v;
        _v = (unsigned int)(z % umod());
        return *this;
    }
    mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }

    mint operator+() const { return *this; }
    mint operator-() const { return mint() - *this; }

    mint pow(long long n) const {
        assert(0 <= n);
        mint x = *this, r = 1;
        while (n) {
            if (n & 1) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    mint inv() const {
        if (prime) {
            assert(_v);
            return pow(umod() - 2);
        } else {
            auto eg = internal::inv_gcd(_v, m);
            assert(eg.first == 1);
            return eg.second;
        }
    }

    friend mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    friend mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    friend mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    friend mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    friend bool operator==(const mint& lhs, const mint& rhs) {
        return lhs._v == rhs._v;
    }
    friend bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs._v != rhs._v;
    }

  private:
    unsigned int _v;
    static constexpr unsigned int umod() { return m; }
    static constexpr bool prime = internal::is_prime<m>;
};

template <int id> struct dynamic_modint : internal::modint_base {
    using mint = dynamic_modint;

  public:
    static int mod() { return (int)(bt.umod()); }
    static void set_mod(int m) {
        assert(1 <= m);
        bt = internal::barrett(m);
    }
    static mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }

    dynamic_modint() : _v(0) {}
    template <class T, internal::is_signed_int_t<T>* = nullptr>
    dynamic_modint(T v) {
        long long x = (long long)(v % (long long)(mod()));
        if (x < 0) x += mod();
        _v = (unsigned int)(x);
    }
    template <class T, internal::is_unsigned_int_t<T>* = nullptr>
    dynamic_modint(T v) {
        _v = (unsigned int)(v % mod());
    }

    unsigned int val() const { return _v; }

    mint& operator++() {
        _v++;
        if (_v == umod()) _v = 0;
        return *this;
    }
    mint& operator--() {
        if (_v == 0) _v = umod();
        _v--;
        return *this;
    }
    mint operator++(int) {
        mint result = *this;
        ++*this;
        return result;
    }
    mint operator--(int) {
        mint result = *this;
        --*this;
        return result;
    }

    mint& operator+=(const mint& rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator-=(const mint& rhs) {
        _v += mod() - rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator*=(const mint& rhs) {
        _v = bt.mul(_v, rhs._v);
        return *this;
    }
    mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }

    mint operator+() const { return *this; }
    mint operator-() const { return mint() - *this; }

    mint pow(long long n) const {
        assert(0 <= n);
        mint x = *this, r = 1;
        while (n) {
            if (n & 1) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    mint inv() const {
        auto eg = internal::inv_gcd(_v, mod());
        assert(eg.first == 1);
        return eg.second;
    }

    friend mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    friend mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    friend mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    friend mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    friend bool operator==(const mint& lhs, const mint& rhs) {
        return lhs._v == rhs._v;
    }
    friend bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs._v != rhs._v;
    }

  private:
    unsigned int _v;
    static internal::barrett bt;
    static unsigned int umod() { return bt.umod(); }
};
template <int id> internal::barrett dynamic_modint<id>::bt(998244353);

using modint998244353 = static_modint<998244353>;
using modint1000000007 = static_modint<1000000007>;
using modint = dynamic_modint<-1>;

namespace internal {

template <class T>
using is_static_modint = std::is_base_of<internal::static_modint_base, T>;

template <class T>
using is_static_modint_t = std::enable_if_t<is_static_modint<T>::value>;

template <class> struct is_dynamic_modint : public std::false_type {};
template <int id>
struct is_dynamic_modint<dynamic_modint<id>> : public std::true_type {};

template <class T>
using is_dynamic_modint_t = std::enable_if_t<is_dynamic_modint<T>::value>;

}  // namespace internal

}  // namespace atcoder


#line 17 "Source.cpp"
using mint = atcoder::modint1000000007;

#define int long long
mint dp[60][60][60][60];
void solve()
{
  int cnts[4];
  REP(i, 4)
  {
    cin >> cnts[i];
  }
  int t;
  cin >> t;
  cin.ignore();
  vector<vector<string>> inputs;
  REP(tea, t)
  {
    string l;
    getline(cin, l);
    vector<string> gogo;
    string b;
    l.push_back(' ');
    REP(i, l.size())
    {
      if (l[i] == ' ')
      {
        if (b != "")
          gogo.push_back(b);
        b.clear();
      }
      else
      {
        b.push_back(l[i]);
      }
    }
    gogo[0].pop_back();
    inputs.push_back(gogo);
  }
  map<string, vector<int>> seqs;
  reverse(ALL(inputs));
  for (auto x : inputs)
  {
    vector<int> tmps;
    for (int q = 1; q < x.size(); ++q)
    {
      if (x[q][0] == '[')
      {
        int cnt = 0;
        string s = "ATGC";
        for (auto y : x[q])
        {
          REP(t, 4)
          {
            if (s[t] == y)
            {
              cnt |= (1 << t);
            }
          }
        }
        tmps.push_back(cnt);
      }
      else
      {
        vector<int> hoge = seqs[x[q]];
        for (auto y : hoge)
        {
          tmps.push_back(y);
        }
      }
      if (tmps.size() > 300)
        break;
    }
    seqs[x[0]] = tmps;
  }
  vector<int> target = seqs[inputs.back()[0]];
  if (target.size() != cnts[0] + cnts[1] + cnts[2] + cnts[3])
  {
    cout << 0 << endl;
    return;
  }
  dp[0][0][0][0] = 1;
  REP(i, cnts[0] + 1)
  {
    REP(q, cnts[1] + 1)
    {
      REP(j, cnts[2] + 1)
      {
        REP(t, cnts[3] + 1)
        {
          int go = i + q + j + t;
          if (i != cnts[0] and (target[go] & 1))
          {
            dp[i + 1][q][j][t] += dp[i][q][j][t];
          }

          if (q != cnts[1] and (target[go] & 2))
          {
            dp[i][q + 1][j][t] += dp[i][q][j][t];
          }

          if (j != cnts[2] and (target[go] & 4))
          {
            dp[i][q][j + 1][t] += dp[i][q][j][t];
          }

          if (t != cnts[3] and (target[go] & 8))
          {
            dp[i][q][j][t + 1] += dp[i][q][j][t];
          }
        }
      }
    }
  }
  cout << dp[cnts[0]][cnts[1]][cnts[2]][cnts[3]].val() << endl;
}

#undef int

// generated by oj-template v4.7.2
// (https://github.com/online-judge-tools/template-generator)
int main()
{
  // Fasterize input/output script
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  cout << fixed << setprecision(100);
  // scanf/printf user should delete this fasterize input/output script

  int t = 1;
  // cin >> t; // comment out if solving multi testcase
  for (int testCase = 1; testCase <= t; ++testCase)
  {
    solve();
  }
  return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 54140
final_rank: 7

code_snippet: #include <cassert>
#include <numeric>
#include <type_traits>

#ifdef _MSC_VER
#include <intrin.h>
#endif


#include <utility>

#ifdef _MSC_VER
#include <intrin.h>
#endif

namespace atcoder {

namespace internal {

constexpr long long safe_mod(long long x, long long m) {
    x %= m;
    if (x < 0) x += m;
    return x;
}

struct barrett {
    unsigned int _m;
    unsigned long long im;

    explicit barrett(unsigned int m) : _m(m), im((unsigned long long)(-1) / m + 1) {}

    unsigned int umod() const { return _m; }

    unsigned int mul(unsigned int a, unsigned int b) const {

        unsigned long long z = a;
        z *= b;
#ifdef _MSC_VER
        unsigned long long x;
        _umul128(z, im, &x);
#else
        unsigned long long x =
            (unsigned long long)(((unsigned __int128)(z)*im) >> 64);
#endif
        unsigned int v = (unsigned int)(z - x * _m);
        if (_m <= v) v += _m;
        return v;
    }
};

constexpr long long pow_mod_constexpr(long long x, long long n, int m) {
    if (m == 1) return 0;
    unsigned int _m = (unsigned int)(m);
    unsigned long long r = 1;
    unsigned long long y = safe_mod(x, m);
    while (n) {
        if (n & 1) r = (r * y) % _m;
        y = (y * y) % _m;
        n >>= 1;
    }
    return r;
}

constexpr bool is_prime_constexpr(int n) {
    if (n <= 1) return false;
    if (n == 2 || n == 7 || n == 61) return true;
    if (n % 2 == 0) return false;
    long long d = n - 1;
    while (d % 2 == 0) d /= 2;
    constexpr long long bases[3] = {2, 7, 61};
    for (long long a : bases) {
        long long t = d;
        long long y = pow_mod_constexpr(a, t, n);
        while (t != n - 1 && y != 1 && y != n - 1) {
            y = y * y % n;
            t <<= 1;
        }
        if (y != n - 1 && t % 2 == 0) {
            return false;
        }
    }
    return true;
}
template <int n> constexpr bool is_prime = is_prime_constexpr(n);

constexpr std::pair<long long, long long> inv_gcd(long long a, long long b) {
    a = safe_mod(a, b);
    if (a == 0) return {b, 0};

    long long s = b, t = a;
    long long m0 = 0, m1 = 1;

    while (t) {
        long long u = s / t;
        s -= t * u;
        m0 -= m1 * u;  // |m1 * u| <= |m1| * s <= b


        auto tmp = s;
        s = t;
        t = tmp;
        tmp = m0;
        m0 = m1;
        m1 = tmp;
    }
    if (m0 < 0) m0 += b / s;
    return {s, m0};
}

constexpr int primitive_root_constexpr(int m) {
    if (m == 2) return 1;
    if (m == 167772161) return 3;
    if (m == 469762049) return 3;
    if (m == 754974721) return 11;
    if (m == 998244353) return 3;
    int divs[20] = {};
    divs[0] = 2;
    int cnt = 1;
    int x = (m - 1) / 2;
    while (x % 2 == 0) x /= 2;
    for (int i = 3; (long long)(i)*i <= x; i += 2) {
        if (x % i == 0) {
            divs[cnt++] = i;
            while (x % i == 0) {
                x /= i;
            }
        }
    }
    if (x > 1) {
        divs[cnt++] = x;
    }
    for (int g = 2;; g++) {
        bool ok = true;
        for (int i = 0; i < cnt; i++) {
            if (pow_mod_constexpr(g, (m - 1) / divs[i], m) == 1) {
                ok = false;
                break;
            }
        }
        if (ok) return g;
    }
}
template <int m> constexpr int primitive_root = primitive_root_constexpr(m);

unsigned long long floor_sum_unsigned(unsigned long long n,
                                      unsigned long long m,
                                      unsigned long long a,
                                      unsigned long long b) {
    unsigned long long ans = 0;
    while (true) {
        if (a >= m) {
            ans += n * (n - 1) / 2 * (a / m);
            a %= m;
        }
        if (b >= m) {
            ans += n * (b / m);
            b %= m;
        }

        unsigned long long y_max = a * n + b;
        if (y_max < m) break;
        n = (unsigned long long)(y_max / m);
        b = (unsigned long long)(y_max % m);
        std::swap(m, a);
    }
    return ans;
}

}  // namespace internal

}  // namespace atcoder


#include <cassert>
#include <numeric>
#include <type_traits>

namespace atcoder {

namespace internal {

#ifndef _MSC_VER
template <class T>
using is_signed_int128 =
    typename std::conditional<std::is_same<T, __int128_t>::value ||
                                  std::is_same<T, __int128>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using is_unsigned_int128 =
    typename std::conditional<std::is_same<T, __uint128_t>::value ||
                                  std::is_same<T, unsigned __int128>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using make_unsigned_int128 =
    typename std::conditional<std::is_same<T, __int128_t>::value,
                              __uint128_t,
                              unsigned __int128>;

template <class T>
using is_integral = typename std::conditional<std::is_integral<T>::value ||
                                                  is_signed_int128<T>::value ||
                                                  is_unsigned_int128<T>::value,
                                              std::true_type,
                                              std::false_type>::type;

template <class T>
using is_signed_int = typename std::conditional<(is_integral<T>::value &&
                                                 std::is_signed<T>::value) ||
                                                    is_signed_int128<T>::value,
                                                std::true_type,
                                                std::false_type>::type;

template <class T>
using is_unsigned_int =
    typename std::conditional<(is_integral<T>::value &&
                               std::is_unsigned<T>::value) ||
                                  is_unsigned_int128<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<
    is_signed_int128<T>::value,
    make_unsigned_int128<T>,
    typename std::conditional<std::is_signed<T>::value,
                              std::make_unsigned<T>,
                              std::common_type<T>>::type>::type;

#else

template <class T> using is_integral = typename std::is_integral<T>;

template <class T>
using is_signed_int =
    typename std::conditional<is_integral<T>::value && std::is_signed<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using is_unsigned_int =
    typename std::conditional<is_integral<T>::value &&
                                  std::is_unsigned<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<is_signed_int<T>::value,
                                              std::make_unsigned<T>,
                                              std::common_type<T>>::type;

#endif

template <class T>
using is_signed_int_t = std::enable_if_t<is_signed_int<T>::value>;

template <class T>
using is_unsigned_int_t = std::enable_if_t<is_unsigned_int<T>::value>;

template <class T> using to_unsigned_t = typename to_unsigned<T>::type;

}  // namespace internal

}  // namespace atcoder


namespace atcoder {

namespace internal {

struct modint_base {};
struct static_modint_base : modint_base {};

template <class T> using is_modint = std::is_base_of<modint_base, T>;
template <class T> using is_modint_t = std::enable_if_t<is_modint<T>::value>;

}  // namespace internal

template <int m, std::enable_if_t<(1 <= m)>* = nullptr>
struct static_modint : internal::static_modint_base {
    using mint = static_modint;

  public:
    static constexpr int mod() { return m; }
    static mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }

    static_modint() : _v(0) {}
    template <class T, internal::is_signed_int_t<T>* = nullptr>
    static_modint(T v) {
        long long x = (long long)(v % (long long)(umod()));
        if (x < 0) x += umod();
        _v = (unsigned int)(x);
    }
    template <class T, internal::is_unsigned_int_t<T>* = nullptr>
    static_modint(T v) {
        _v = (unsigned int)(v % umod());
    }

    unsigned int val() const { return _v; }

    mint& operator++() {
        _v++;
        if (_v == umod()) _v = 0;
        return *this;
    }
    mint& operator--() {
        if (_v == 0) _v = umod();
        _v--;
        return *this;
    }
    mint operator++(int) {
        mint result = *this;
        ++*this;
        return result;
    }
    mint operator--(int) {
        mint result = *this;
        --*this;
        return result;
    }

    mint& operator+=(const mint& rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator-=(const mint& rhs) {
        _v -= rhs._v;
        if (_v >= umod()) _v += umod();
        return *this;
    }
    mint& operator*=(const mint& rhs) {
        unsigned long long z = _v;
        z *= rhs._v;
        _v = (unsigned int)(z % umod());
        return *this;
    }
    mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }

    mint operator+() const { return *this; }
    mint operator-() const { return mint() - *this; }

    mint pow(long long n) const {
        assert(0 <= n);
        mint x = *this, r = 1;
        while (n) {
            if (n & 1) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    mint inv() const {
        if (prime) {
            assert(_v);
            return pow(umod() - 2);
        } else {
            auto eg = internal::inv_gcd(_v, m);
            assert(eg.first == 1);
            return eg.second;
        }
    }

    friend mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    friend mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    friend mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    friend mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    friend bool operator==(const mint& lhs, const mint& rhs) {
        return lhs._v == rhs._v;
    }
    friend bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs._v != rhs._v;
    }

  private:
    unsigned int _v;
    static constexpr unsigned int umod() { return m; }
    static constexpr bool prime = internal::is_prime<m>;
};

template <int id> struct dynamic_modint : internal::modint_base {
    using mint = dynamic_modint;

  public:
    static int mod() { return (int)(bt.umod()); }
    static void set_mod(int m) {
        assert(1 <= m);
        bt = internal::barrett(m);
    }
    static mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }

    dynamic_modint() : _v(0) {}
    template <class T, internal::is_signed_int_t<T>* = nullptr>
    dynamic_modint(T v) {
        long long x = (long long)(v % (long long)(mod()));
        if (x < 0) x += mod();
        _v = (unsigned int)(x);
    }
    template <class T, internal::is_unsigned_int_t<T>* = nullptr>
    dynamic_modint(T v) {
        _v = (unsigned int)(v % mod());
    }

    unsigned int val() const { return _v; }

    mint& operator++() {
        _v++;
        if (_v == umod()) _v = 0;
        return *this;
    }
    mint& operator--() {
        if (_v == 0) _v = umod();
        _v--;
        return *this;
    }
    mint operator++(int) {
        mint result = *this;
        ++*this;
        return result;
    }
    mint operator--(int) {
        mint result = *this;
        --*this;
        return result;
    }

    mint& operator+=(const mint& rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator-=(const mint& rhs) {
        _v += mod() - rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator*=(const mint& rhs) {
        _v = bt.mul(_v, rhs._v);
        return *this;
    }
    mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }

    mint operator+() const { return *this; }
    mint operator-() const { return mint() - *this; }

    mint pow(long long n) const {
        assert(0 <= n);
        mint x = *this, r = 1;
        while (n) {
            if (n & 1) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    mint inv() const {
        auto eg = internal::inv_gcd(_v, mod());
        assert(eg.first == 1);
        return eg.second;
    }

    friend mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    friend mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    friend mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    friend mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    friend bool operator==(const mint& lhs, const mint& rhs) {
        return lhs._v == rhs._v;
    }
    friend bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs._v != rhs._v;
    }

  private:
    unsigned int _v;
    static internal::barrett bt;
    static unsigned int umod() { return bt.umod(); }
};
template <int id> internal::barrett dynamic_modint<id>::bt(998244353);

using modint998244353 = static_modint<998244353>;
using modint1000000007 = static_modint<1000000007>;
using modint = dynamic_modint<-1>;

namespace internal {

template <class T>
using is_static_modint = std::is_base_of<internal::static_modint_base, T>;

template <class T>
using is_static_modint_t = std::enable_if_t<is_static_modint<T>::value>;

template <class> struct is_dynamic_modint : public std::false_type {};
template <int id>
struct is_dynamic_modint<dynamic_modint<id>> : public std::true_type {};

template <class T>
using is_dynamic_modint_t = std::enable_if_t<is_dynamic_modint<T>::value>;

}  // namespace internal

}  // namespace atcoder

#include <iostream>
#include <algorithm>
#include <numeric>
#include <vector>
#include <array>
#include <string>
#include <map>

using namespace std;
using mint = atcoder::modint1000000007;

const string atgc{"ATGC"};

vector<string> parse(const string& s) {
    vector<string> ss{""};
    for (auto c : s) {
        if (c == ' ') {
            ss.push_back("");
        } else if (c != ':') {
            ss.back().push_back(c);
        }
    }
    return ss;
}

void solve() {
    array<int, 4> gs;
    for (auto& g : gs) cin >> g;

    int m;
    cin >> m;
    {
        string tmp;
        getline(cin, tmp);
    }

    vector<vector<string>> sss(m);
    for (auto& ss : sss) {
        string s;
        getline(cin, s);
        ss = parse(s);
    }
    reverse(sss.begin(), sss.end());

    map<string, vector<int>> mp;
    for (auto ss : sss) {
        string name = ss.front();
        ss.erase(ss.begin());

        vector<int> cnt(16, 0);
        for (const auto& s : ss) {
            if (s.front() == '[') {
                int b = 0;
                for (auto c : s) {
                    for (int i = 0; i < 4; ++i) {
                        if (c == atgc[i]) b |= (1 << i);
                    }
                }
                ++cnt[b];
            } else {
                auto v = mp[s];
                for (int b = 0; b < 16; ++b) cnt[b] += v[b];
            }
        }

        mp[name] = cnt;
    }

    auto cnt = mp[sss.back().front()];

    if (accumulate(cnt.begin(), cnt.end(), 0) !=
        accumulate(gs.begin(), gs.end(), 0)) {
        cout << "0\n";
        return;
    }

    map<array<int, 4>, mint> dp, ndp;
    dp[{0, 0, 0, 0}] = 1;

    for (int b = 0; b < 16; ++b) {
        while (cnt[b]--) {
            ndp.clear();
            for (const auto& [is, p] : dp) {
                for (int c = 0; c < 4; ++c) {
                    if ((~b >> c) & 1) continue;

                    auto nis = is;
                    if (++nis[c] > gs[c]) continue;
                    ndp[nis] += p;
                }
            }
            swap(dp, ndp);
        }
    }

    cout << dp[gs].val() << "\n";
}

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

    solve();

    return 0;
}
accuracy: 1
time_ms: 1230
memory_kb: 13320
final_rank: 13

code_snippet: #include <cassert>
#include <numeric>
#include <type_traits>

#ifdef _MSC_VER
#include <intrin.h>
#endif


#include <utility>

#ifdef _MSC_VER
#include <intrin.h>
#endif

namespace atcoder {

namespace internal {

constexpr long long safe_mod(long long x, long long m) {
    x %= m;
    if (x < 0) x += m;
    return x;
}

struct barrett {
    unsigned int _m;
    unsigned long long im;

    explicit barrett(unsigned int m) : _m(m), im((unsigned long long)(-1) / m + 1) {}

    unsigned int umod() const { return _m; }

    unsigned int mul(unsigned int a, unsigned int b) const {

        unsigned long long z = a;
        z *= b;
#ifdef _MSC_VER
        unsigned long long x;
        _umul128(z, im, &x);
#else
        unsigned long long x =
            (unsigned long long)(((unsigned __int128)(z)*im) >> 64);
#endif
        unsigned int v = (unsigned int)(z - x * _m);
        if (_m <= v) v += _m;
        return v;
    }
};

constexpr long long pow_mod_constexpr(long long x, long long n, int m) {
    if (m == 1) return 0;
    unsigned int _m = (unsigned int)(m);
    unsigned long long r = 1;
    unsigned long long y = safe_mod(x, m);
    while (n) {
        if (n & 1) r = (r * y) % _m;
        y = (y * y) % _m;
        n >>= 1;
    }
    return r;
}

constexpr bool is_prime_constexpr(int n) {
    if (n <= 1) return false;
    if (n == 2 || n == 7 || n == 61) return true;
    if (n % 2 == 0) return false;
    long long d = n - 1;
    while (d % 2 == 0) d /= 2;
    constexpr long long bases[3] = {2, 7, 61};
    for (long long a : bases) {
        long long t = d;
        long long y = pow_mod_constexpr(a, t, n);
        while (t != n - 1 && y != 1 && y != n - 1) {
            y = y * y % n;
            t <<= 1;
        }
        if (y != n - 1 && t % 2 == 0) {
            return false;
        }
    }
    return true;
}
template <int n> constexpr bool is_prime = is_prime_constexpr(n);

constexpr std::pair<long long, long long> inv_gcd(long long a, long long b) {
    a = safe_mod(a, b);
    if (a == 0) return {b, 0};

    long long s = b, t = a;
    long long m0 = 0, m1 = 1;

    while (t) {
        long long u = s / t;
        s -= t * u;
        m0 -= m1 * u;  // |m1 * u| <= |m1| * s <= b


        auto tmp = s;
        s = t;
        t = tmp;
        tmp = m0;
        m0 = m1;
        m1 = tmp;
    }
    if (m0 < 0) m0 += b / s;
    return {s, m0};
}

constexpr int primitive_root_constexpr(int m) {
    if (m == 2) return 1;
    if (m == 167772161) return 3;
    if (m == 469762049) return 3;
    if (m == 754974721) return 11;
    if (m == 998244353) return 3;
    int divs[20] = {};
    divs[0] = 2;
    int cnt = 1;
    int x = (m - 1) / 2;
    while (x % 2 == 0) x /= 2;
    for (int i = 3; (long long)(i)*i <= x; i += 2) {
        if (x % i == 0) {
            divs[cnt++] = i;
            while (x % i == 0) {
                x /= i;
            }
        }
    }
    if (x > 1) {
        divs[cnt++] = x;
    }
    for (int g = 2;; g++) {
        bool ok = true;
        for (int i = 0; i < cnt; i++) {
            if (pow_mod_constexpr(g, (m - 1) / divs[i], m) == 1) {
                ok = false;
                break;
            }
        }
        if (ok) return g;
    }
}
template <int m> constexpr int primitive_root = primitive_root_constexpr(m);

unsigned long long floor_sum_unsigned(unsigned long long n,
                                      unsigned long long m,
                                      unsigned long long a,
                                      unsigned long long b) {
    unsigned long long ans = 0;
    while (true) {
        if (a >= m) {
            ans += n * (n - 1) / 2 * (a / m);
            a %= m;
        }
        if (b >= m) {
            ans += n * (b / m);
            b %= m;
        }

        unsigned long long y_max = a * n + b;
        if (y_max < m) break;
        n = (unsigned long long)(y_max / m);
        b = (unsigned long long)(y_max % m);
        std::swap(m, a);
    }
    return ans;
}

}  // namespace internal

}  // namespace atcoder


#include <cassert>
#include <numeric>
#include <type_traits>

namespace atcoder {

namespace internal {

#ifndef _MSC_VER
template <class T>
using is_signed_int128 =
    typename std::conditional<std::is_same<T, __int128_t>::value ||
                                  std::is_same<T, __int128>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using is_unsigned_int128 =
    typename std::conditional<std::is_same<T, __uint128_t>::value ||
                                  std::is_same<T, unsigned __int128>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using make_unsigned_int128 =
    typename std::conditional<std::is_same<T, __int128_t>::value,
                              __uint128_t,
                              unsigned __int128>;

template <class T>
using is_integral = typename std::conditional<std::is_integral<T>::value ||
                                                  is_signed_int128<T>::value ||
                                                  is_unsigned_int128<T>::value,
                                              std::true_type,
                                              std::false_type>::type;

template <class T>
using is_signed_int = typename std::conditional<(is_integral<T>::value &&
                                                 std::is_signed<T>::value) ||
                                                    is_signed_int128<T>::value,
                                                std::true_type,
                                                std::false_type>::type;

template <class T>
using is_unsigned_int =
    typename std::conditional<(is_integral<T>::value &&
                               std::is_unsigned<T>::value) ||
                                  is_unsigned_int128<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<
    is_signed_int128<T>::value,
    make_unsigned_int128<T>,
    typename std::conditional<std::is_signed<T>::value,
                              std::make_unsigned<T>,
                              std::common_type<T>>::type>::type;

#else

template <class T> using is_integral = typename std::is_integral<T>;

template <class T>
using is_signed_int =
    typename std::conditional<is_integral<T>::value && std::is_signed<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using is_unsigned_int =
    typename std::conditional<is_integral<T>::value &&
                                  std::is_unsigned<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<is_signed_int<T>::value,
                                              std::make_unsigned<T>,
                                              std::common_type<T>>::type;

#endif

template <class T>
using is_signed_int_t = std::enable_if_t<is_signed_int<T>::value>;

template <class T>
using is_unsigned_int_t = std::enable_if_t<is_unsigned_int<T>::value>;

template <class T> using to_unsigned_t = typename to_unsigned<T>::type;

}  // namespace internal

}  // namespace atcoder


namespace atcoder {

namespace internal {

struct modint_base {};
struct static_modint_base : modint_base {};

template <class T> using is_modint = std::is_base_of<modint_base, T>;
template <class T> using is_modint_t = std::enable_if_t<is_modint<T>::value>;

}  // namespace internal

template <int m, std::enable_if_t<(1 <= m)>* = nullptr>
struct static_modint : internal::static_modint_base {
    using mint = static_modint;

  public:
    static constexpr int mod() { return m; }
    static mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }

    static_modint() : _v(0) {}
    template <class T, internal::is_signed_int_t<T>* = nullptr>
    static_modint(T v) {
        long long x = (long long)(v % (long long)(umod()));
        if (x < 0) x += umod();
        _v = (unsigned int)(x);
    }
    template <class T, internal::is_unsigned_int_t<T>* = nullptr>
    static_modint(T v) {
        _v = (unsigned int)(v % umod());
    }

    unsigned int val() const { return _v; }

    mint& operator++() {
        _v++;
        if (_v == umod()) _v = 0;
        return *this;
    }
    mint& operator--() {
        if (_v == 0) _v = umod();
        _v--;
        return *this;
    }
    mint operator++(int) {
        mint result = *this;
        ++*this;
        return result;
    }
    mint operator--(int) {
        mint result = *this;
        --*this;
        return result;
    }

    mint& operator+=(const mint& rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator-=(const mint& rhs) {
        _v -= rhs._v;
        if (_v >= umod()) _v += umod();
        return *this;
    }
    mint& operator*=(const mint& rhs) {
        unsigned long long z = _v;
        z *= rhs._v;
        _v = (unsigned int)(z % umod());
        return *this;
    }
    mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }

    mint operator+() const { return *this; }
    mint operator-() const { return mint() - *this; }

    mint pow(long long n) const {
        assert(0 <= n);
        mint x = *this, r = 1;
        while (n) {
            if (n & 1) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    mint inv() const {
        if (prime) {
            assert(_v);
            return pow(umod() - 2);
        } else {
            auto eg = internal::inv_gcd(_v, m);
            assert(eg.first == 1);
            return eg.second;
        }
    }

    friend mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    friend mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    friend mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    friend mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    friend bool operator==(const mint& lhs, const mint& rhs) {
        return lhs._v == rhs._v;
    }
    friend bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs._v != rhs._v;
    }

  private:
    unsigned int _v;
    static constexpr unsigned int umod() { return m; }
    static constexpr bool prime = internal::is_prime<m>;
};

template <int id> struct dynamic_modint : internal::modint_base {
    using mint = dynamic_modint;

  public:
    static int mod() { return (int)(bt.umod()); }
    static void set_mod(int m) {
        assert(1 <= m);
        bt = internal::barrett(m);
    }
    static mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }

    dynamic_modint() : _v(0) {}
    template <class T, internal::is_signed_int_t<T>* = nullptr>
    dynamic_modint(T v) {
        long long x = (long long)(v % (long long)(mod()));
        if (x < 0) x += mod();
        _v = (unsigned int)(x);
    }
    template <class T, internal::is_unsigned_int_t<T>* = nullptr>
    dynamic_modint(T v) {
        _v = (unsigned int)(v % mod());
    }

    unsigned int val() const { return _v; }

    mint& operator++() {
        _v++;
        if (_v == umod()) _v = 0;
        return *this;
    }
    mint& operator--() {
        if (_v == 0) _v = umod();
        _v--;
        return *this;
    }
    mint operator++(int) {
        mint result = *this;
        ++*this;
        return result;
    }
    mint operator--(int) {
        mint result = *this;
        --*this;
        return result;
    }

    mint& operator+=(const mint& rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator-=(const mint& rhs) {
        _v += mod() - rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator*=(const mint& rhs) {
        _v = bt.mul(_v, rhs._v);
        return *this;
    }
    mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }

    mint operator+() const { return *this; }
    mint operator-() const { return mint() - *this; }

    mint pow(long long n) const {
        assert(0 <= n);
        mint x = *this, r = 1;
        while (n) {
            if (n & 1) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    mint inv() const {
        auto eg = internal::inv_gcd(_v, mod());
        assert(eg.first == 1);
        return eg.second;
    }

    friend mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    friend mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    friend mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    friend mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    friend bool operator==(const mint& lhs, const mint& rhs) {
        return lhs._v == rhs._v;
    }
    friend bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs._v != rhs._v;
    }

  private:
    unsigned int _v;
    static internal::barrett bt;
    static unsigned int umod() { return bt.umod(); }
};
template <int id> internal::barrett dynamic_modint<id>::bt(998244353);

using modint998244353 = static_modint<998244353>;
using modint1000000007 = static_modint<1000000007>;
using modint = dynamic_modint<-1>;

namespace internal {

template <class T>
using is_static_modint = std::is_base_of<internal::static_modint_base, T>;

template <class T>
using is_static_modint_t = std::enable_if_t<is_static_modint<T>::value>;

template <class> struct is_dynamic_modint : public std::false_type {};
template <int id>
struct is_dynamic_modint<dynamic_modint<id>> : public std::true_type {};

template <class T>
using is_dynamic_modint_t = std::enable_if_t<is_dynamic_modint<T>::value>;

}  // namespace internal

}  // namespace atcoder

#include <iostream>
#include <algorithm>
#include <numeric>
#include <vector>
#include <string>
#include <map>

using namespace std;
using mint = atcoder::modint1000000007;

const string atgc{"ATGC"};

vector<string> parse(const string& s) {
    vector<string> ss{""};
    for (auto c : s) {
        if (c == ' ') {
            ss.push_back("");
        } else if (c != ':') {
            ss.back().push_back(c);
        }
    }
    return ss;
}

void solve() {
    vector<int> gs(4);
    for (auto& g : gs) cin >> g;

    int m;
    cin >> m;
    {
        string tmp;
        getline(cin, tmp);
    }

    vector<vector<string>> sss(m);
    for (auto& ss : sss) {
        string s;
        getline(cin, s);
        ss = parse(s);
    }
    reverse(sss.begin(), sss.end());

    map<string, vector<int>> mp;
    for (auto ss : sss) {
        string name = ss.front();
        ss.erase(ss.begin());

        vector<int> cnt(16, 0);
        for (const auto& s : ss) {
            if (s.front() == '[') {
                int b = 0;
                for (auto c : s) {
                    for (int i = 0; i < 4; ++i) {
                        if (c == atgc[i]) b |= (1 << i);
                    }
                }
                ++cnt[b];
            } else {
                auto v = mp[s];
                for (int b = 0; b < 16; ++b) cnt[b] += v[b];
            }
        }

        mp[name] = cnt;
    }

    auto cnt = mp[sss.back().front()];

    if (accumulate(cnt.begin(), cnt.end(), 0) !=
        accumulate(gs.begin(), gs.end(), 0)) {
        cout << "0\n";
        return;
    }

    map<vector<int>, mint> dp;
    dp[{0, 0, 0, 0}] = 1;

    for (int b = 0; b < 16; ++b) {
        while (cnt[b]--) {
            map<vector<int>, mint> ndp;
            for (const auto& [is, p] : dp) {
                for (int c = 0; c < 4; ++c) {
                    if ((~b >> c) & 1) continue;

                    auto nis = is;
                    if (++nis[c] > gs[c]) continue;
                    ndp[nis] += p;
                }
            }

            swap(dp, ndp);
        }
    }

    cout << dp[gs].val() << "\n";
}

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

    solve();

    return 0;
}
accuracy: 1
time_ms: 1790
memory_kb: 20772
final_rank: 19

code_snippet: #pragma GCC optimize("Ofast")
#include <iostream>
#include <vector>
#include <algorithm>
#include <map>
#include <queue>
#include <cstdio>
#include <ctime>
#include <assert.h>
#include <chrono>
#include <random>
#include <numeric>
#include <set>
#include <deque>
#include <stack>
#include <sstream>
#include <utility>
#include <cstring>
#include <unordered_map>
#include <unordered_set>
#include <tuple>
#include <array>
using namespace std;
typedef long long int ll;
typedef unsigned long long ull;

mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
ll myRand(ll B) {
    return (ull)rng() % B;
}

constexpr ll mod = 1e9+7;

int na,nt,ng,nc;
ll dp[55][55][55][55];

int main(){
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    for(int i=0;i<55;i++){
        for(int j=0;j<55;j++){
            for(int k=0;k<55;k++){
                for(int l=0;l<55;l++){
                    dp[i][j][k][l] = -1;
                }
            }
        }
    }
    cin >> na >> nt >> ng >> nc;
    int m; cin >> m;
    string base; getline(cin,base);
    map<string,vector<string>> mp;
    for(int i=0;i<m;i++){
        string s; getline(cin,s);
        stringstream ss(s);
        string fr; ss >> fr;
        fr.pop_back();
        if(i == 0){
            base = fr;
        }
        string t;
        while(ss >> t){
            mp[fr].push_back(t);
        }
    }
    vector<int> v;
    auto dfs=[&](auto self,string s)->void{
        if(v.size()>na+nt+ng+nc){
            cout << 0 << endl;
            exit(0);
        }
        for(auto t:mp[s]){
            if(t[0]=='['){
                int u = 0;
                for(int j=1;j+1<t.size();j++){
                    if(t[j] == 'A') u |= (1<<0);
                    if(t[j] == 'T') u |= (1<<1);
                    if(t[j] == 'G') u |= (1<<2);
                    if(t[j] == 'C') u |= (1<<3);
                }
                v.push_back(u);
            }
            else{
                self(self, t);
            }
        }
        if(v.size()>na+nt+ng+nc){
            cout << 0 << endl;
            exit(0);
        }
    };
    dfs(dfs,base);
    // for(auto ss:v){
    //     cout << ss << endl;
    // }
    auto cal = [&](auto self,int a,int t,int g,int c)->ll{
        if(dp[a][t][g][c] != -1){
            return dp[a][t][g][c];
        }
        if(a == na and t == nt and c == nc and g == ng){
            dp[a][t][g][c] = 1;
            return 1;
        }
        if(a > na or t > nt or g > ng or c > nc){
            dp[a][t][g][c] = 0;
            return 0;
        }
        ll res = 0;
        int u = v[a+t+c+g];
        if((1<<0)&u){
            res += self(self,a+1,t,g,c);
        }
        if((1<<1)&u){
            res += self(self,a,t+1,g,c);
        }
        if((1<<2)&u){
            res += self(self,a,t,g+1,c);
        }
        if((1<<3)&u){
            res += self(self,a,t,g,c+1);
        }
        res %= mod;
        dp[a][t][g][c] = res;
        return res;
    };
    cout << cal(cal,0,0,0,0) << endl;
}
accuracy: 1
time_ms: 80
memory_kb: 74976
final_rank: 12

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

template <uint64_t Modulus> class modint {
    using i64 = int64_t;
    using u32 = uint32_t;
    using u64 = uint64_t;

    static_assert(Modulus < static_cast<uint32_t>(1) << 31, "Modulus must be less than 2**31");
    static constexpr u32 mod = Modulus;
    u32 v;

public:
    constexpr modint(const i64 x = 0) noexcept : v(x < 0 ? mod - 1 - (-(x + 1) % mod) : x % mod) {}
    constexpr u32& val() noexcept { return v; }
    constexpr const u32& val() const noexcept { return v; }
    constexpr modint operator+(const modint& rhs) const noexcept { return modint(*this) += rhs; }
    constexpr modint operator-(const modint& rhs) const noexcept { return modint(*this) -= rhs; }
    constexpr modint operator*(const modint& rhs) const noexcept { return modint(*this) *= rhs; }
    constexpr modint operator/(const modint& rhs) const noexcept { return modint(*this) /= rhs; }
    constexpr modint& operator+=(const modint& rhs) noexcept {
        v += rhs.v;
        if (v >= mod) v -= mod;
        return *this;
    }
    constexpr modint& operator-=(const modint& rhs) noexcept {
        if (v < rhs.v) v += mod;
        v -= rhs.v;
        return *this;
    }
    constexpr modint& operator*=(const modint& rhs) noexcept {
        v = (u64)v * rhs.v % mod;
        return *this;
    }
    constexpr modint& operator/=(const modint& rhs) noexcept { return *this *= rhs.inv(); }
    constexpr modint pow(long long n) const noexcept {
        assert(0 <= n);
        modint self(*this), res(1);
        while (n > 0) {
            if (n & 1) res *= self;
            self *= self;
            n >>= 1;
        }
        return res;
    }
    constexpr modint inv() const noexcept {
        assert(*this != 0);
        return pow(mod - 2);
    }
    constexpr modint& operator++() noexcept {
        if (++v == mod) v = 0;
        return *this;
    }
    constexpr modint& operator--() noexcept {
        if (v == 0) v = mod;
        return --v, *this;
    }
    constexpr modint operator++(int) noexcept {
        modint t = *this;
        return ++*this, t;
    }
    constexpr modint operator--(int) noexcept {
        modint t = *this;
        return --*this, t;
    }
    constexpr modint operator-() const noexcept { return modint(mod - v); }
    template <class T> friend constexpr modint operator+(T x, modint y) noexcept { return modint(x) + y; }
    template <class T> friend constexpr modint operator-(T x, modint y) noexcept { return modint(x) - y; }
    template <class T> friend constexpr modint operator*(T x, modint y) noexcept { return modint(x) * y; }
    template <class T> friend constexpr modint operator/(T x, modint y) noexcept { return modint(x) / y; }
    constexpr bool operator==(const modint& rhs) const noexcept { return v == rhs.v; }
    constexpr bool operator!=(const modint& rhs) const noexcept { return v != rhs.v; }
    constexpr bool operator!() const noexcept { return !v; }
    friend std::istream& operator>>(std::istream& s, modint& rhs) noexcept {
        i64 v;
        rhs = modint{(s >> v, v)};
        return s;
    }
    friend std::ostream& operator<<(std::ostream& s, const modint& rhs) noexcept { return s << rhs.v; }
};

/**
 * @brief modint
 * @docs docs/modulo/modint.md
 */

const long long MOD = 1000000007;
using mint = modint<MOD>;
const int MAX_N = 52;
mint dp[MAX_N][MAX_N][MAX_N][MAX_N];

int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    int Na, Nb, Nc, Nd;
    cin >> Na >> Nb >> Nc >> Nd;
    int m;
    cin >> m;
    vector<string> S(m);
    getline(cin, S[0]);
    for (auto& s : S) getline(cin, s);

    size_t sum = Na + Nb + Nc + Nd;
    vector<vector<int>> decomp(m);
    map<string, int> mp;

    auto ctoi = [](char c) {
        if (c == 'A') return 0;
        if (c == 'T') return 1;
        if (c == 'G') return 2;
        if (c == 'C') return 3;
        assert(false);
    };
    auto calc = [&](int idx, const string& s) {
        size_t cur = 0;
        string name = "";
        while (s[cur] != ':') name += s[cur++];
        cur += 2;
        for (; cur < s.size() and decomp[idx].size() <= sum + 1; cur++) {
            if (s[cur] == '[') {
                int mask = 0;
                cur++;
                while (s[cur] != ']') mask |= 1 << (ctoi(s[cur++]));
                decomp[idx].emplace_back(mask);
                cur++;
            } else {
                string add = "";
                while (cur < s.size() and s[cur] != ' ') add += s[cur++];
                int x = mp[add];
                for (auto& val : decomp[x]) decomp[idx].emplace_back(val);
            }
        }
        mp[name] = idx;
    };
    for (int i = m - 1; i >= 0; i--) calc(i, S[i]);

    if (decomp[0].size() > sum) {
        cout << 0 << '\n';
        return 0;
    }

    dp[0][0][0][0] = 1;
    for (int p = 0; p < int(decomp[0].size()); p++) {
        int mask = decomp[0][p];
        for (int i = min(Na, p); i >= 0; i--) {
            for (int j = min(Nb, p - i); j >= 0; j--) {
                for (int k = min(Nc, p - (i + j)); k >= 0; k--) {
                    for (int l = min(Nd, p - (i + j + k)); l >= 0; l--) {
                        mint& val = dp[i][j][k][l];
                        if (val == 0) continue;
                        if (i + 1 <= Na and (mask >> 0 & 1)) dp[i + 1][j][k][l] += val;
                        if (j + 1 <= Nb and (mask >> 1 & 1)) dp[i][j + 1][k][l] += val;
                        if (k + 1 <= Nc and (mask >> 2 & 1)) dp[i][j][k + 1][l] += val;
                        if (l + 1 <= Nd and (mask >> 3 & 1)) dp[i][j][k][l + 1] += val;
                        val = 0;
                    }
                }
            }
        }
    }

    mint ans = dp[Na][Nb][Nc][Nd];
    cout << ans << '\n';
    return 0;
}
accuracy: 1
time_ms: 640
memory_kb: 31360
final_rank: 10

code_snippet: #define LOCAL
#include <bits/stdc++.h>
using namespace std;
#pragma region Macros
typedef long long ll;
typedef __int128_t i128;
typedef unsigned int uint;
typedef unsigned long long ull;
#define ALL(x) (x).begin(), (x).end()

template <typename T> istream& operator>>(istream& is, vector<T>& v) {
    for (T& x : v) is >> x;
    return is;
}
template <typename T> ostream& operator<<(ostream& os, const vector<T>& v) {
    for (int i = 0; i < (int)v.size(); i++) {
        os << v[i] << (i + 1 == (int)v.size() ? "" : " ");
    }
    return os;
}
template <typename T, typename U> ostream& operator<<(ostream& os, const pair<T, U>& p) {
    os << '(' << p.first << ',' << p.second << ')';
    return os;
}
template <typename T, typename U> ostream& operator<<(ostream& os, const map<T, U>& m) {
    os << '{';
    for (auto itr = m.begin(); itr != m.end();) {
        os << '(' << itr->first << ',' << itr->second << ')';
        if (++itr != m.end()) os << ',';
    }
    os << '}';
    return os;
}
template <typename T, typename U> ostream& operator<<(ostream& os, const unordered_map<T, U>& m) {
    os << '{';
    for (auto itr = m.begin(); itr != m.end();) {
        os << '(' << itr->first << ',' << itr->second << ')';
        if (++itr != m.end()) os << ',';
    }
    os << '}';
    return os;
}
template <typename T> ostream& operator<<(ostream& os, const set<T>& s) {
    os << '{';
    for (auto itr = s.begin(); itr != s.end();) {
        os << *itr;
        if (++itr != s.end()) os << ',';
    }
    os << '}';
    return os;
}
template <typename T> ostream& operator<<(ostream& os, const multiset<T>& s) {
    os << '{';
    for (auto itr = s.begin(); itr != s.end();) {
        os << *itr;
        if (++itr != s.end()) os << ',';
    }
    os << '}';
    return os;
}
template <typename T> ostream& operator<<(ostream& os, const unordered_set<T>& s) {
    os << '{';
    for (auto itr = s.begin(); itr != s.end();) {
        os << *itr;
        if (++itr != s.end()) os << ',';
    }
    os << '}';
    return os;
}
template <typename T> ostream& operator<<(ostream& os, const deque<T>& v) {
    for (int i = 0; i < (int)v.size(); i++) {
        os << v[i] << (i + 1 == (int)v.size() ? "" : " ");
    }
    return os;
}

template <int i, typename T> void print_tuple(ostream&, const T&) {}
template <int i, typename T, typename H, class... Args> void print_tuple(ostream& os, const T& t) {
    if (i) os << ',';
    os << get<i>(t);
    print_tuple<i + 1, T, Args...>(os, t);
}
template <typename... Args> ostream& operator<<(ostream& os, const tuple<Args...>& t) {
    os << '{';
    print_tuple<0, tuple<Args...>, Args...>(os, t);
    return os << '}';
}

void debug_out() { cerr << '\n'; }
template <class Head, class... Tail> void debug_out(Head&& head, Tail&&... tail) {
    cerr << head;
    if (sizeof...(Tail) > 0) cerr << ", ";
    debug_out(move(tail)...);
}
#ifdef LOCAL
#define debug(...)                                                                   \
    cerr << " ";                                                                     \
    cerr << #__VA_ARGS__ << " :[" << __LINE__ << ":" << __FUNCTION__ << "]" << '\n'; \
    cerr << " ";                                                                     \
    debug_out(__VA_ARGS__)
#else
#define debug(...) 42
#endif

template <typename T> T gcd(T x, T y) { return y != 0 ? gcd(y, x % y) : x; }
template <typename T> T lcm(T x, T y) { return x / gcd(x, y) * y; }

int topbit(signed t) { return t == 0 ? -1 : 31 - __builtin_clz(t); }
int topbit(long long t) { return t == 0 ? -1 : 63 - __builtin_clzll(t); }
int botbit(signed a) { return a == 0 ? 32 : __builtin_ctz(a); }
int botbit(long long a) { return a == 0 ? 64 : __builtin_ctzll(a); }
int popcount(signed t) { return __builtin_popcount(t); }
int popcount(long long t) { return __builtin_popcountll(t); }
bool ispow2(int i) { return i && (i & -i) == i; }

template <class T> T ceil(T x, T y) {
    assert(y >= 1);
    return (x > 0 ? (x + y - 1) / y : x / y);
}
template <class T> T floor(T x, T y) {
    assert(y >= 1);
    return (x > 0 ? x / y : (x - y + 1) / y);
}

template <class T1, class T2> inline bool chmin(T1& a, T2 b) {
    if (a > b) {
        a = b;
        return true;
    }
    return false;
}
template <class T1, class T2> inline bool chmax(T1& a, T2 b) {
    if (a < b) {
        a = b;
        return true;
    }
    return false;
}
#pragma endregion

#include <cassert>
#include <cstdint>
#include <iostream>

template <uint64_t Modulus> class modint {
    using i64 = int64_t;
    using u32 = uint32_t;
    using u64 = uint64_t;

    static_assert(Modulus < static_cast<uint32_t>(1) << 31, "Modulus must be less than 2**31");
    static constexpr u32 mod = Modulus;
    u32 v;

public:
    constexpr modint(const i64 x = 0) noexcept : v(x < 0 ? mod - 1 - (-(x + 1) % mod) : x % mod) {}
    constexpr u32& val() noexcept { return v; }
    constexpr const u32& val() const noexcept { return v; }
    constexpr modint operator+(const modint& rhs) const noexcept { return modint(*this) += rhs; }
    constexpr modint operator-(const modint& rhs) const noexcept { return modint(*this) -= rhs; }
    constexpr modint operator*(const modint& rhs) const noexcept { return modint(*this) *= rhs; }
    constexpr modint operator/(const modint& rhs) const noexcept { return modint(*this) /= rhs; }
    constexpr modint& operator+=(const modint& rhs) noexcept {
        v += rhs.v;
        if (v >= mod) v -= mod;
        return *this;
    }
    constexpr modint& operator-=(const modint& rhs) noexcept {
        if (v < rhs.v) v += mod;
        v -= rhs.v;
        return *this;
    }
    constexpr modint& operator*=(const modint& rhs) noexcept {
        v = (u64)v * rhs.v % mod;
        return *this;
    }
    constexpr modint& operator/=(const modint& rhs) noexcept { return *this *= rhs.inv(); }
    constexpr modint pow(long long n) const noexcept {
        assert(0 <= n);
        modint self(*this), res(1);
        while (n > 0) {
            if (n & 1) res *= self;
            self *= self;
            n >>= 1;
        }
        return res;
    }
    constexpr modint inv() const noexcept {
        assert(*this != 0);
        return pow(mod - 2);
    }
    constexpr modint& operator++() noexcept {
        if (++v == mod) v = 0;
        return *this;
    }
    constexpr modint& operator--() noexcept {
        if (v == 0) v = mod;
        return --v, *this;
    }
    constexpr modint operator++(int) noexcept {
        modint t = *this;
        return ++*this, t;
    }
    constexpr modint operator--(int) noexcept {
        modint t = *this;
        return --*this, t;
    }
    constexpr modint operator-() const noexcept { return modint(mod - v); }
    template <class T> friend constexpr modint operator+(T x, modint y) noexcept { return modint(x) + y; }
    template <class T> friend constexpr modint operator-(T x, modint y) noexcept { return modint(x) - y; }
    template <class T> friend constexpr modint operator*(T x, modint y) noexcept { return modint(x) * y; }
    template <class T> friend constexpr modint operator/(T x, modint y) noexcept { return modint(x) / y; }
    constexpr bool operator==(const modint& rhs) const noexcept { return v == rhs.v; }
    constexpr bool operator!=(const modint& rhs) const noexcept { return v != rhs.v; }
    constexpr bool operator!() const noexcept { return !v; }
    friend std::istream& operator>>(std::istream& s, modint& rhs) noexcept {
        i64 v;
        rhs = modint{(s >> v, v)};
        return s;
    }
    friend std::ostream& operator<<(std::ostream& s, const modint& rhs) noexcept { return s << rhs.v; }
};

/**
 * @brief modint
 * @docs docs/modulo/modint.md
 */

const int INF = 1e9;
const long long IINF = 1e18;
const int dx[4] = {1, 0, -1, 0}, dy[4] = {0, 1, 0, -1};
const char dir[4] = {'D', 'R', 'U', 'L'};
const long long MOD = 1000000007;
// const long long MOD = 998244353;

using mint = modint<MOD>;
const int MAX_N = 52;
mint dp[MAX_N][MAX_N][MAX_N][MAX_N];

int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    int Na, Nb, Nc, Nd;
    cin >> Na >> Nb >> Nc >> Nd;
    int m;
    cin >> m;
    vector<string> S(m);
    getline(cin, S[0]);
    for (auto& s : S) getline(cin, s);

    size_t sum = Na + Nb + Nc + Nd;
    vector<vector<int>> decomp(m);
    map<string, int> mp;

    auto ctoi = [](char c) {
        if (c == 'A') return 0;
        if (c == 'T') return 1;
        if (c == 'G') return 2;
        if (c == 'C') return 3;
        assert(false);
    };
    auto calc = [&](int idx, const string& s) {
        size_t cur = 0;
        string name = "";
        while (s[cur] != ':') name += s[cur++];
        cur += 2;
        for (; cur < s.size() and decomp[idx].size() <= sum + 1; cur++) {
            if (s[cur] == '[') {
                int mask = 0;
                cur++;
                while (s[cur] != ']') mask |= 1 << (ctoi(s[cur++]));
                decomp[idx].emplace_back(mask);
                cur++;
            } else {
                string add = "";
                while (cur < s.size() and s[cur] != ' ') add += s[cur++];
                int x = mp[add];
                for (auto& val : decomp[x]) decomp[idx].emplace_back(val);
            }
        }
        mp[name] = idx;
    };
    for (int i = m - 1; i >= 0; i--) calc(i, S[i]);

    if (decomp[0].size() > sum) {
        cout << 0 << '\n';
        return 0;
    }

    dp[0][0][0][0] = 1;
    for (int p = 0; p < int(decomp[0].size()); p++) {
        int mask = decomp[0][p];
        for (int i = min(Na, p); i >= 0; i--) {
            for (int j = min(Nb, p - i); j >= 0; j--) {
                for (int k = min(Nc, p - (i + j)); k >= 0; k--) {
                    for (int l = min(Nd, p - (i + j + k)); l >= 0; l--) {
                        mint& val = dp[i][j][k][l];
                        if (val == 0) continue;
                        if (i + 1 <= Na and (mask >> 0 & 1)) dp[i + 1][j][k][l] += val;
                        if (j + 1 <= Nb and (mask >> 1 & 1)) dp[i][j + 1][k][l] += val;
                        if (k + 1 <= Nc and (mask >> 2 & 1)) dp[i][j][k + 1][l] += val;
                        if (l + 1 <= Nd and (mask >> 3 & 1)) dp[i][j][k][l + 1] += val;
                        val = 0;
                    }
                }
            }
        }
    }

    mint ans = dp[Na][Nb][Nc][Nd];
    cout << ans << '\n';
    return 0;
}
accuracy: 1
time_ms: 640
memory_kb: 31284
final_rank: 9

code_snippet: #pragma GCC target("avx2")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
#include <bits/stdc++.h>
//#include <atcoder/all>
using namespace std;
//using namespace atcoder;
#define DEBUG
#ifdef DEBUG
template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
    os << '(' << p.first << ',' << p.second << ')';
    return os;
}
template <class T> ostream &operator<<(ostream &os, const vector<T> &v) {
    os << '{';
    for(int i = 0; i < (int)v.size(); i++) {
        if(i) { os << ','; }
        os << v[i];
    }
    os << '}';
    return os;
}
void debugg() { cerr << endl; }
template <class T, class... Args>
void debugg(const T &x, const Args &... args) {
    cerr << " " << x;
    debugg(args...);
}
#define debug(...)                                                             \
    cerr << __LINE__ << " [" << #__VA_ARGS__ << "]: ", debugg(__VA_ARGS__)
#define dump(x) cerr << __LINE__ << " " << #x << " = " << (x) << endl
#else
#define debug(...) (void(0))
#define dump(x) (void(0))
#endif
using namespace std;
typedef long long ll;
typedef vector<ll> vl;
typedef vector<vl> vvl;
typedef vector<char> vc;
typedef vector<string> vs;
typedef vector<bool> vb;
typedef vector<double> vd;
typedef pair<ll,ll> P;
typedef pair<int,int> pii;
typedef vector<P> vpl;
typedef tuple<ll,ll,ll> tapu;
#define rep(i,n) for(int i=0; i<(n); i++)
#define REP(i,a,b) for(int i=(a); i<(b); i++)
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
const int inf = (1<<30)-1;
const ll linf = 1LL<<61;
const int MAX = 25000000;
int dy[8] = {0,1,0,-1,1,-1,-1,1};
int dx[8] = {-1,0,1,0,1,-1,1,-1};
const double pi = acos(-1);
const double eps = 1e-8;
template<typename T1,typename T2> inline bool chmin(T1 &a,T2 b){
	if(a>b){
		a = b; return true;
	}
	else return false;
}
template<typename T1,typename T2> inline bool chmax(T1 &a,T2 b){
	if(a<b){
		a = b; return true;
	}
	else return false;
}
template<typename T> inline void print(T &a){
    int sz = a.size();
    for(auto itr = a.begin(); itr != a.end(); itr++){
		cout << *itr;
        sz--;
        if(sz) cout << " ";
	}
    cout << "\n";
}
template<typename T1,typename T2> inline void print2(T1 a, T2 b){
	cout << a << " " << b << "\n";
}
template<typename T1,typename T2,typename T3> inline void print3(T1 a, T2 b, T3 c){
	cout << a << " " << b << " " << c << "\n";
}
void mark() {cout << "#" << "\n";}
ll pcount(ll x) {return __builtin_popcountll(x);}
const int mod = 1e9 + 7;
//const int mod = 998244353;

template <int mod> struct ModInt {
    int x;

    ModInt() : x(0) {}

    ModInt(int64_t y) : x(y >= 0 ? y % mod : (mod - (-y) % mod) % mod) {}

    ModInt &operator+=(const ModInt &p) {
        if((x += p.x) >= mod) x -= mod;
        return *this;
    }

    ModInt &operator-=(const ModInt &p) {
        if((x += mod - p.x) >= mod) x -= mod;
        return *this;
    }

    ModInt &operator*=(const ModInt &p) {
        x = (int)(1LL * x * p.x % mod);
        return *this;
    }

    ModInt &operator/=(const ModInt &p) {
        *this *= p.inverse();
        return *this;
    }

    ModInt operator-() const { return ModInt(-x); }

    ModInt operator+(const ModInt &p) const { return ModInt(*this) += p; }

    ModInt operator-(const ModInt &p) const { return ModInt(*this) -= p; }

    ModInt operator*(const ModInt &p) const { return ModInt(*this) *= p; }

    ModInt operator/(const ModInt &p) const { return ModInt(*this) /= p; }

    bool operator==(const ModInt &p) const { return x == p.x; }

    bool operator!=(const ModInt &p) const { return x != p.x; }

    ModInt inverse() const {
        int a = x, b = mod, u = 1, v = 0, t;
        while(b > 0) {
            t = a / b;
            swap(a -= t * b, b);
            swap(u -= t * v, v);
        }
        return ModInt(u);
    }

    ModInt pow(int64_t n) const {
        ModInt ret(1), mul(x);
        while(n > 0) {
            if(n & 1) ret *= mul;
            mul *= mul;
            n >>= 1;
        }
        return ret;
    }

    friend ostream &operator<<(ostream &os, const ModInt &p) {
        return os << p.x;
    }

    friend istream &operator>>(istream &is, ModInt &a) {
        int64_t t;
        is >> t;
        a = ModInt<mod>(t);
        return (is);
    }

    static int get_mod() { return mod; }
};

using mint = ModInt<mod>;

mint dp[2][55][55][55];

map<string,vs> mp;

int main(){
    int na,nt,ng,nc; cin >> na >> nt >> ng >> nc;
    int n = na+nt+ng+nc;
    int m; cin >> m;
    string s;
    vs v;
    string now = "@";
    string fi;
    while(cin >> s){
        if(s.back() == ':'){
            s.pop_back();
            if(now == "@") fi = s;
            else mp[now] = v;
            v.clear();
            now = s;
        }else{
            v.push_back(s);
        }
    }
    mp[now] = v;
    vs ls;
    auto dfs = [&](auto &&dfs, string &t) -> void {
        for(auto x : mp[t]){
            if(ls.size() > n){
                cout << 0 << endl;
                exit(0);
            }
            if(x.back() == ']'){
                ls.push_back(x);
            }else{
                dfs(dfs, x);
            }
        }
    };
    dfs(dfs, fi);
    if(ls.size() != n){
        cout << 0 << endl;
        return 0;
    }
    dp[0][na][nt][ng] = 1;
    rep(i,n){
        rep(a,na+1) rep(t,nt+1) rep(g,ng+1) dp[1][a][t][g] = 0;
        string u = ls[i];
        rep(a,na+1) rep(t,nt+1) rep(g,ng+1){
            int c = n-i-a-t-g;
            if(c<0 || c>nc) continue;
            for(auto ch : u){
                if(ch=='A' && a>0) dp[1][a-1][t][g] += dp[0][a][t][g];
                if(ch=='T' && t>0) dp[1][a][t-1][g] += dp[0][a][t][g];
                if(ch=='G' && g>0) dp[1][a][t][g-1] += dp[0][a][t][g];
                if(ch=='C' && c>0) dp[1][a][t][g] += dp[0][a][t][g]; 
            }
        }
        swap(dp[0],dp[1]);
    }
    cout << dp[0][0][0][0] << endl;
}
accuracy: 1
time_ms: 150
memory_kb: 4760
final_rank: 1

code_snippet: #pragma GCC target("avx2")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
#include <bits/stdc++.h>
//#include <atcoder/all>
using namespace std;
//using namespace atcoder;
#define DEBUG
#ifdef DEBUG
template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
    os << '(' << p.first << ',' << p.second << ')';
    return os;
}
template <class T> ostream &operator<<(ostream &os, const vector<T> &v) {
    os << '{';
    for(int i = 0; i < (int)v.size(); i++) {
        if(i) { os << ','; }
        os << v[i];
    }
    os << '}';
    return os;
}
void debugg() { cerr << endl; }
template <class T, class... Args>
void debugg(const T &x, const Args &... args) {
    cerr << " " << x;
    debugg(args...);
}
#define debug(...)                                                             \
    cerr << __LINE__ << " [" << #__VA_ARGS__ << "]: ", debugg(__VA_ARGS__)
#define dump(x) cerr << __LINE__ << " " << #x << " = " << (x) << endl
#else
#define debug(...) (void(0))
#define dump(x) (void(0))
#endif
using namespace std;
typedef long long ll;
typedef vector<ll> vl;
typedef vector<vl> vvl;
typedef vector<char> vc;
typedef vector<string> vs;
typedef vector<bool> vb;
typedef vector<double> vd;
typedef pair<ll,ll> P;
typedef pair<int,int> pii;
typedef vector<P> vpl;
typedef tuple<ll,ll,ll> tapu;
#define rep(i,n) for(int i=0; i<(n); i++)
#define REP(i,a,b) for(int i=(a); i<(b); i++)
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
const int inf = (1<<30)-1;
const ll linf = 1LL<<61;
const int MAX = 25000000;
int dy[8] = {0,1,0,-1,1,-1,-1,1};
int dx[8] = {-1,0,1,0,1,-1,1,-1};
const double pi = acos(-1);
const double eps = 1e-8;
template<typename T1,typename T2> inline bool chmin(T1 &a,T2 b){
	if(a>b){
		a = b; return true;
	}
	else return false;
}
template<typename T1,typename T2> inline bool chmax(T1 &a,T2 b){
	if(a<b){
		a = b; return true;
	}
	else return false;
}
template<typename T> inline void print(T &a){
    int sz = a.size();
    for(auto itr = a.begin(); itr != a.end(); itr++){
		cout << *itr;
        sz--;
        if(sz) cout << " ";
	}
    cout << "\n";
}
template<typename T1,typename T2> inline void print2(T1 a, T2 b){
	cout << a << " " << b << "\n";
}
template<typename T1,typename T2,typename T3> inline void print3(T1 a, T2 b, T3 c){
	cout << a << " " << b << " " << c << "\n";
}
void mark() {cout << "#" << "\n";}
ll pcount(ll x) {return __builtin_popcountll(x);}
const int mod = 1e9 + 7;
//const int mod = 998244353;

template <int mod> struct ModInt {
    int x;

    ModInt() : x(0) {}

    ModInt(int64_t y) : x(y >= 0 ? y % mod : (mod - (-y) % mod) % mod) {}

    ModInt &operator+=(const ModInt &p) {
        if((x += p.x) >= mod) x -= mod;
        return *this;
    }

    ModInt &operator-=(const ModInt &p) {
        if((x += mod - p.x) >= mod) x -= mod;
        return *this;
    }

    ModInt &operator*=(const ModInt &p) {
        x = (int)(1LL * x * p.x % mod);
        return *this;
    }

    ModInt &operator/=(const ModInt &p) {
        *this *= p.inverse();
        return *this;
    }

    ModInt operator-() const { return ModInt(-x); }

    ModInt operator+(const ModInt &p) const { return ModInt(*this) += p; }

    ModInt operator-(const ModInt &p) const { return ModInt(*this) -= p; }

    ModInt operator*(const ModInt &p) const { return ModInt(*this) *= p; }

    ModInt operator/(const ModInt &p) const { return ModInt(*this) /= p; }

    bool operator==(const ModInt &p) const { return x == p.x; }

    bool operator!=(const ModInt &p) const { return x != p.x; }

    ModInt inverse() const {
        int a = x, b = mod, u = 1, v = 0, t;
        while(b > 0) {
            t = a / b;
            swap(a -= t * b, b);
            swap(u -= t * v, v);
        }
        return ModInt(u);
    }

    ModInt pow(int64_t n) const {
        ModInt ret(1), mul(x);
        while(n > 0) {
            if(n & 1) ret *= mul;
            mul *= mul;
            n >>= 1;
        }
        return ret;
    }

    friend ostream &operator<<(ostream &os, const ModInt &p) {
        return os << p.x;
    }

    friend istream &operator>>(istream &is, ModInt &a) {
        int64_t t;
        is >> t;
        a = ModInt<mod>(t);
        return (is);
    }

    static int get_mod() { return mod; }
};

using mint = ModInt<mod>;

mint dp[2][55][55][55];

map<string,vs> mp;

int main(){
    int na,nt,ng,nc; cin >> na >> nt >> ng >> nc;
    int n = na+nt+ng+nc;
    int m; cin >> m;
    string s;
    vs v;
    string now = "@";
    string fi;
    while(cin >> s){
        if(s.back() == ':'){
            s.pop_back();
            if(now == "@") fi = s;
            else mp[now] = v;
            v.clear();
            now = s;
        }else{
            v.push_back(s);
        }
    }
    mp[now] = v;
    vs ls;
    auto dfs = [&](auto &&dfs, string &t) -> void {
        for(auto x : mp[t]){
            if(ls.size() > n){
                cout << 0 << endl;
                exit(0);
            }
            if(x.back() == ']'){
                ls.push_back(x);
            }else{
                dfs(dfs, x);
            }
        }
    };
    dfs(dfs, fi);
    if(ls.size() != n){
        cout << 0 << endl;
        return 0;
    }
    dp[0][na][nt][ng] = 1;
    rep(i,n){
        rep(a,na+1) rep(t,nt+1) rep(g,ng+1) dp[1][a][t][g] = 0;
        string u = ls[i];
        rep(a,na+1) rep(t,nt+1) rep(g,ng+1){
            int c = n-i-a-t-g;
            if(c<0 || c>nc) continue;
            if(u.find('A')<=4 && a>0) dp[1][a-1][t][g] += dp[0][a][t][g];
            if(u.find('T')<=4 && t>0) dp[1][a][t-1][g] += dp[0][a][t][g];
            if(u.find('G')<=4 && g>0) dp[1][a][t][g-1] += dp[0][a][t][g];
            if(u.find('C')<=4 && c>0) dp[1][a][t][g] += dp[0][a][t][g]; 
        }
        swap(dp[0],dp[1]);
    }
    cout << dp[0][0][0][0] << endl;
}
accuracy: 1
time_ms: 200
memory_kb: 4768
final_rank: 3

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

using ll = long long;
using PII = pair<ll, ll>;

#define FOR(i, a, n) for (ll i = (ll)a; i < (ll)n; ++i)
#define REP(i, n) FOR(i, 0, n)
#define ALL(x) x.begin(), x.end()
#define POPCOUNT(x) __builtin_popcount(x)
template <typename T> void chmin(T &a, const T &b) { a = min(a, b); }
template <typename T> void chmax(T &a, const T &b) { a = max(a, b); }

const ll INF = 1LL << 60;
const ll MOD = 1e9 + 7;

struct FastIO {
    FastIO() {
        cin.tie(0);
        ios::sync_with_stdio(0);
    }
} fastiofastio;

vector<string> split(const string &S) {
    vector<string> ret;
    string s = "";
    for (int i = 0; i < S.size(); i++) {
        if (S[i] == ' ') {
            ret.push_back(s);
            s = "";
        } else {
            s.push_back(S[i]);
        }
    }
    ret.push_back(s);
    return ret;
}

vector<string> vec[50];
vector<ll> memo[50];
map<string, int> idx;
int dp[201][51][51][51];

void dfs(int v) {
    if (memo[v].size() != 0)
        return;
    vector<ll> ret(16);
    for (const string &s : vec[v]) {
        if (s[0] == '[') {
            int b = 0;
            for (int i = 1; i + 1 < s.size(); i++) {
                if (s[i] == 'A')
                    b |= 1;
                else if (s[i] == 'T')
                    b |= 2;
                else if (s[i] == 'G')
                    b |= 4;
                else
                    b |= 8;
            }
            ret[b] = min(ret[b] + 1, INF);
        } else {
            int k = idx[s];
            dfs(k);
            for (int i = 0; i < 16; i++)
                ret[i] = min(ret[i] + memo[k][i], INF);
        }
    }
    memo[v] = ret;
}

int main() {
    int Na, Nt, Ng, Nc;
    cin >> Na >> Nt >> Ng >> Nc;
    int m;
    cin >> m;
    string line;
    getline(cin, line);
    for (int i = 0; i < m; i++) {
        getline(cin, line);
        vector<string> ret = split(line);
        string name = ret[0];
        name.pop_back();
        ret.erase(ret.begin());
        idx[name] = i;
        vec[i] = ret;
    }
    dfs(0);
    ll len = 0;
    for (int i = 0; i < 16; i++)
        len = min(len + memo[0][i], INF);
    if (len != Na + Nt + Ng + Nc) {
        cout << 0 << endl;
        return 0;
    }
    len = 0;
    dp[0][0][0][0] = 1;
    for (int i = 0; i < 16; i++) {
        for (int j = 0; j < memo[0][i]; j++) {
            for (int a = 0; a <= Na; a++) {
                if (a > len)
                    break;
                for (int t = 0; t <= Nt; t++) {
                    if (a + t > len)
                        break;
                    for (int g = 0; g <= Ng; g++) {
                        if (a + t + g > len)
                            break;
                        int c = len - (a + t + g);
                        for (int k = 0; k < 4; k++) {
                            if ((i & (1 << k)) == 0)
                                continue;
                            if (k == 0 && a + 1 <= Na)
                                (dp[len + 1][a + 1][t][g] +=
                                 dp[len][a][t][g]) %= MOD;
                            if (k == 1 && t + 1 <= Nt)
                                (dp[len + 1][a][t + 1][g] +=
                                 dp[len][a][t][g]) %= MOD;
                            if (k == 2 && g + 1 <= Ng)
                                (dp[len + 1][a][t][g + 1] +=
                                 dp[len][a][t][g]) %= MOD;
                            if (k == 3 && c + 1 <= Nc)
                                (dp[len + 1][a][t][g] += dp[len][a][t][g]) %=
                                    MOD;
                        }
                    }
                }
            }
            len++;
        }
    }
    cout << dp[len][Na][Nt][Ng] << endl;
}
accuracy: 1
time_ms: 90
memory_kb: 103784
final_rank: 15

code_snippet: #line 1 "a.cpp"
#include<iostream>
#include<map>
#include<vector>
#include<array>
using namespace std;
#line 3 "/home/kotatsugame/library/math/modint.cpp"
#include<utility>
template<int m>
struct modint{
	unsigned int x;
	constexpr modint()noexcept:x(){}
	template<typename T>
	constexpr modint(T x_)noexcept:x((x_%=m)<0?x_+m:x_){}
	constexpr unsigned int val()const noexcept{return x;}
	constexpr modint&operator++()noexcept{if(++x==m)x=0;return*this;}
	constexpr modint&operator--()noexcept{if(x==0)x=m;--x;return*this;}
	constexpr modint operator++(int)noexcept{modint res=*this;++*this;return res;}
	constexpr modint operator--(int)noexcept{modint res=*this;--*this;return res;}
	constexpr modint&operator+=(const modint&a)noexcept{x+=a.x;if(x>=m)x-=m;return*this;}
	constexpr modint&operator-=(const modint&a)noexcept{if(x<a.x)x+=m;x-=a.x;return*this;}
	constexpr modint&operator*=(const modint&a)noexcept{x=(unsigned long long)x*a.x%m;return*this;}
	constexpr modint&operator/=(const modint&a)noexcept{return*this*=a.inv();}
	constexpr modint operator+()const noexcept{return*this;}
	constexpr modint operator-()const noexcept{return modint()-*this;}
	constexpr modint pow(long long n)const noexcept
	{
		if(n<0)return pow(-n).inv();
		modint x=*this,r=1;
		for(;n;x*=x,n>>=1)if(n&1)r*=x;
		return r;
	}
	constexpr modint inv()const noexcept
	{
		int s=x,t=m,x=1,u=0;
		while(t)
		{
			int k=s/t;
			s-=k*t;
			swap(s,t);
			x-=k*u;
			swap(x,u);
		}
		return modint(x);
	}
	friend constexpr modint operator+(const modint&a,const modint&b){return modint(a)+=b;}
	friend constexpr modint operator-(const modint&a,const modint&b){return modint(a)-=b;}
	friend constexpr modint operator*(const modint&a,const modint&b){return modint(a)*=b;}
	friend constexpr modint operator/(const modint&a,const modint&b){return modint(a)/=b;}
	friend constexpr bool operator==(const modint&a,const modint&b){return a.x==b.x;}
	friend constexpr bool operator!=(const modint&a,const modint&b){return a.x!=b.x;}
	friend ostream&operator<<(ostream&os,const modint&a){return os<<a.x;}
	friend istream&operator>>(istream&is,modint&a){long long v;is>>v;a=modint(v);return is;}
};
#line 7 "a.cpp"
using mint=modint<(int)1e9+7>;
mint dp[51][51][51][51];
string DNA="ATGC";
int N[4],L;
int M;
map<string,vector<string> >mp;
vector<int>X;
void f(string s)
{
	if(s[0]=='[')
	{
		int T=0;
		for(int i=1;i+1<s.size();i++)
		{
			for(int j=0;j<4;j++)if(s[i]==DNA[j])T|=1<<j;
		}
		X.push_back(T);
		return;
	}
	for(const string&t:mp[s])
	{
		f(t);
		if(X.size()>L)break;
	}
}
main()
{
	for(int i=0;i<4;i++)
	{
		cin>>N[i];
		L+=N[i];
	}
	cin>>M;
	cin.ignore();
	string st;
	for(int i=0;i<M;i++)
	{
		string in;
		getline(cin,in);
		string A="";
		vector<string>B;
		int id=0;
		while(in[id]!=':')
		{
			A+=in[id++];
		}
		if(i==0)st=A;
		id++;
		id++;
		while(id<in.size())
		{
			string now="";
			while(id<in.size()&&in[id]!=' ')
			{
				now+=in[id++];
			}
			B.push_back(now);
			id++;
		}
		mp[A]=B;
	}
	f(st);
	if(X.size()!=L)
	{
		cout<<0<<endl;
		return 0;
	}
	dp[N[0]][N[1]][N[2]][N[3]]=1;
	for(int i=0;i<L;i++)
	{
		int rest=L-i;
		for(int a=0;a<=N[0]&&a<=rest;a++)
			for(int b=0;b<=N[1]&&a+b<=rest;b++)
				for(int c=0;c<=N[2]&&a+b+c<=rest;c++)
		{
			int d=rest-a-b-c;
			if(d>N[3])continue;
			if(X[i]&1&&a>0)
			{
				dp[a-1][b][c][d]+=dp[a][b][c][d];
			}
			if(X[i]&2&&b>0)
			{
				dp[a][b-1][c][d]+=dp[a][b][c][d];
			}
			if(X[i]&4&&c>0)
			{
				dp[a][b][c-1][d]+=dp[a][b][c][d];
			}
			if(X[i]&8&&d>0)
			{
				dp[a][b][c][d-1]+=dp[a][b][c][d];
			}
		}
	}
	cout<<dp[0][0][0][0]<<endl;
}
accuracy: 1
time_ms: 150
memory_kb: 29140
final_rank: 5

code_snippet: #include <bits/stdc++.h>

using namespace std;

#define REP(i, n) for (int i=0; i<(n); ++i)
#define RREP(i, n) for (int i=(int)(n)-1; i>=0; --i)
#define FOR(i, a, n) for (int i=(a); i<(n); ++i)
#define RFOR(i, a, n) for (int i=(int)(n)-1; i>=(a); --i)

#define SZ(x) ((int)(x).size())
#define ALL(x) (x).begin(),(x).end()

#define DUMP(x) cerr<<#x<<" = "<<(x)<<endl
#define DEBUG(x) cerr<<#x<<" = "<<(x)<<" (L"<<__LINE__<<")"<<endl;

template<class T>
ostream &operator<<(ostream &os, const vector<T> &v) {
  os << "[";
  REP(i, SZ(v)) {
    if (i) os << ", ";
    os << v[i];
  }
  return os << "]";
}

template<class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
  return os << "(" << p.first << " " << p.second << ")";
}

template<class T>
bool chmax(T &a, const T &b) {
  if (a < b) {
    a = b;
    return true;
  }
  return false;
}

template<class T>
bool chmin(T &a, const T &b) {
  if (b < a) {
    a = b;
    return true;
  }
  return false;
}

using ll = long long;
using ull = unsigned long long;
using ld = long double;
using P = pair<int, int>;
using vi = vector<int>;
using vll = vector<ll>;
using vvi = vector<vi>;
using vvll = vector<vll>;

const ll MOD = 1e9 + 7;
const int INF = INT_MAX / 2;
const ll LINF = LLONG_MAX / 2;
const ld eps = 1e-9;

vvi result;

map<string, int> mp;
vector<vector<string>> rule;
int su = 0;
void read(int i, int &len) {
  REP(j, SZ(rule[i])) {
    if(len > su) return;
    if(rule[i][j][0] == '[') {
      len++;
      vi v;
      for(int k=1;k<SZ(rule[i][j])-1;k++) {
        switch(rule[i][j][k]) {
          case 'A':
            v.push_back(0);
            break;
          case 'T':
            v.push_back(1);
            break;
          case 'G':
            v.push_back(2);
            break;
          case 'C':
            v.push_back(3);
            break;
          default:
            assert(false);
            break;
        }
      }
      result.emplace_back(v);
    } else {
      read(mp[rule[i][j]], len);
      if(len > su) return;
    }
  }
}

int dp[201][51][51][51] = {0};

int main() {
  cin.tie(0);
  ios::sync_with_stdio(false);
  cout << fixed << setprecision(10);

  vi v(4); cin >> v[0] >> v[1] >> v[2] >> v[3];
  su = accumulate(ALL(v), 0);
  int m; cin >> m;
  cin.ignore();
  REP(i, m) {
    string tmp;
    getline(cin, tmp);

    string s = "";
    int pos = 0;
    bool init = true;
    while(pos < SZ(tmp)) {
      while(pos < SZ(tmp) && tmp[pos] != ' ') {
        s += tmp[pos];
        pos++;
      }

      if(init) {
        init = false;
        s.pop_back();
        mp[s] = i;
        rule.emplace_back(vector<string>());
      } else {
        rule[i].emplace_back(s);
      }
      s = "";
      pos++;
    }
  }

  int len = 0;
  read(0, len);
  if(len != su) {
    cout << 0 << endl;
    return 0;
  }

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

  int dj[4] = {1, 0, 0, 0};
  int dk[4] = {0, 1, 0, 0};
  int dl[4] = {0, 0, 1, 0};

  REP(i, su) {
    REP(j, v[0]+1) {
      REP(k, v[1]+1) {
        REP(l, v[2]+1) {
          for(auto &e: result[i]) {
            int nj = j + dj[e];
            int nk = k + dk[e];
            int nl = l + dl[e];

            if(nj <= v[0] && nk <= v[1] && nl <= v[2]) {
              dp[i+1][nj][nk][nl] = (dp[i+1][nj][nk][nl] + dp[i][j][k][l]) % MOD;
            }
          }
        }
      }
    }
  }

  cout << dp[su][v[0]][v[1]][v[2]] << endl;

  return 0;
}
accuracy: 1
time_ms: 210
memory_kb: 105248
final_rank: 16

code_snippet: #include <bits/stdc++.h>

using namespace std;

using ll = long long;
using P = pair<int,int>;
using PP = pair<P,P>;

constexpr ll MOD = 1000000007;
constexpr char DNA[] = "ATGC";

int n[4], m, L = 0;
map<string,vector<string> > syn;
vector<int> ls;

// 構文解析
void parse(string s){
    string label = "";
    auto itr = s.begin();
    while(*itr != ':'){
        label.push_back(*itr);
        itr++;
    }
    itr++;
    while(itr != s.end()){
        string t = "";
        itr++;
        while(itr != s.end() && *itr != ' '){
            t.push_back(*itr);
            itr++;
        }
        syn[label].push_back(t);
    }
}

bool dfs(string& label){
    for(auto &s : syn[label]){
        if(s[0] == '['){
            int x = 0;
            for(int i=1;i<int(s.size()-1);i++){
                for(int j=0;j<4;j++){
                    if(s[i] == DNA[j]) x |= 1<<j;
                }
            }
            ls.push_back(x);
            if(ls.size() > L) return false;
        }else{
            if(!dfs(s)){
                return false;
            }
        }
    }
    return true;
}

ll dp[2][52][52][52][52]{};  // i文字目(%2)まで見て各文字が[a][t][g][c]の通り

int main(){
    for(int i=0;i<4;i++){
        cin >> n[i];
        L += n[i];
    }
    cin >> m;
    vector<string> s(m);
    string tmp;
    getline(cin, tmp);
    for(int i=0;i<m;i++){
        getline(cin, s[i]);
        parse(s[i]);
    }

    // 構文木からi文字目の終端記号を求める
    string start = s[0].substr(0,s[0].find(':'));
    if(!dfs(start) || ls.size() != L){
        cout << 0 << endl;
    }else{
        dp[0][0][0][0][0] = 1;
        for(int i=0;i<L;i++){
            for(int a=0;a<=min(i,n[0]);a++){
                for(int t=0;t<=min(i-a,n[1]);t++){
                    for(int g=0;g<=min(i-a-t,n[2]);g++){
                        int c = i-a-t-g;
                        if(c > n[3]) continue;
                        if((ls[i])&1){
                            dp[(i&1)^1][a+1][t][g][c] += dp[i&1][a][t][g][c];
                            dp[(i&1)^1][a+1][t][g][c] %= MOD;;
                        }
                        if((ls[i]>>1)&1){
                            dp[(i&1)^1][a][t+1][g][c] += dp[i&1][a][t][g][c];
                            dp[(i&1)^1][a][t+1][g][c] %= MOD;
                        }
                        if((ls[i]>>2)&1){
                            dp[(i&1)^1][a][t][g+1][c] += dp[i&1][a][t][g][c];
                            dp[(i&1)^1][a][t][g+1][c] %= MOD;
                        }
                        if((ls[i]>>3)&1){
                            dp[(i&1)^1][a][t][g][c+1] += dp[i&1][a][t][g][c];
                            dp[(i&1)^1][a][t][g][c+1] %= MOD;
                        }
                    }
                }
            }
        }
        cout << dp[L&1][n[0]][n[1]][n[2]][n[3]] << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 230
memory_kb: 115224
final_rank: 18

code_snippet: #include <bits/stdc++.h>

using namespace std;

using ll = long long;
using P = pair<int,int>;
using PP = pair<P,P>;

constexpr ll MOD = 1000000007;
constexpr char DNA[] = "ATGC";

int n[4], m, L = 0;
map<string,vector<string> > syn;
vector<int> ls;

// 構文解析
void parse(string s){
    string label = "";
    auto itr = s.begin();
    while(*itr != ':'){
        label.push_back(*itr);
        itr++;
    }
    itr++;
    while(itr != s.end()){
        string t = "";
        itr++;
        while(itr != s.end() && *itr != ' '){
            t.push_back(*itr);
            itr++;
        }
        syn[label].push_back(t);
    }
}

bool dfs(string& label){
    for(auto &s : syn[label]){
        if(s[0] == '['){
            int x = 0;
            for(int i=1;i<int(s.size()-1);i++){
                for(int j=0;j<4;j++){
                    if(s[i] == DNA[j]) x |= 1<<j;
                }
            }
            ls.push_back(x);
            if(ls.size() > L) return false;
        }else{
            if(!dfs(s)){
                return false;
            }
        }
    }
    return true;
}

ll dp[2][52][52][52][52]{};  // i文字目(%2)まで見て各文字が[a][t][g][c]の通り

int main(){
    for(int i=0;i<4;i++){
        cin >> n[i];
        L += n[i];
    }
    cin >> m;
    vector<string> s(m);
    string tmp;
    getline(cin, tmp);
    for(int i=0;i<m;i++){
        getline(cin, s[i]);
        parse(s[i]);
    }

    // 構文木からi文字目の終端記号を求める
    string start = s[0].substr(0,s[0].find(':'));
    if(!dfs(start) || ls.size() != L){
        cout << 0 << endl;
    }else{
        dp[0][0][0][0][0] = 1;
        for(int i=0;i<L;i++){
            for(int a=0;a<=min(i,n[0]);a++){
                for(int t=0;t<=min(i-a,n[1]);t++){
                    for(int g=0;g<=min(i-a-t,n[2]);g++){
                        int c = i-a-t-g;
                        if(c > n[3]) continue;
                        if((ls[i])&1){
                            dp[(i&1)^1][a+1][t][g][c] += dp[i&1][a][t][g][c];
                            dp[(i&1)^1][a+1][t][g][c] %= MOD;;
                        }
                        if((ls[i]>>1)&1){
                            dp[(i&1)^1][a][t+1][g][c] += dp[i&1][a][t][g][c];
                            dp[(i&1)^1][a][t+1][g][c] %= MOD;
                        }
                        if((ls[i]>>2)&1){
                            dp[(i&1)^1][a][t][g+1][c] += dp[i&1][a][t][g][c];
                            dp[(i&1)^1][a][t][g+1][c] %= MOD;
                        }
                        if((ls[i]>>3)&1){
                            dp[(i&1)^1][a][t][g][c+1] += dp[i&1][a][t][g][c];
                            dp[(i&1)^1][a][t][g][c+1] %= MOD;
                        }
                    }
                }
            }
            // for(int a=0;a<=n[0];a++){
            //     for(int t=0;t<=n[1];t++){
            //         for(int g=0;g<=n[2];g++){
            //             int c = i-a-t-g;
            //             dp[i&1][a][t][g][c] = 0;
            //             dp[(i&1)^1][a][t][g][c] %= MOD;
                        
            //         }
            //     }
            // }
        }
        cout << dp[L&1][n[0]][n[1]][n[2]][n[3]] << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 210
memory_kb: 115300
final_rank: 17

code_snippet: #include "iostream"
#include "climits"
#include "list"
#include "queue"
#include "stack"
#include "set"
#include "functional"
#include "algorithm"
#include "string"
#include "map"
#include "unordered_map"
#include "unordered_set"
#include "iomanip"
#include "cmath"
#include "random"
#include "bitset"
#include "cstdio"
#include "numeric"
#include "cassert"
#include "ctime"

using namespace std;

constexpr long long int MOD = 1000000007;
//constexpr int MOD = 1000000007;
//constexpr int MOD = 998244353;
//constexpr long long int MOD = 998244353;
constexpr double EPS = 1e-9;

//int N, M, K, T, H, W, L, R;
long long int N, M, K, T, H, W, L, R;

int box[256];
vector<vector<int>>num;
vector<string>s(N);
vector<string>name;
vector<vector<string>>to;
map<string, int>mp;

int dp[52][52][52][52];

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

	box['A'] = 1;
	box['T'] = 2;
	box['G'] = 4;
	box['C'] = 8;
	int a, b, c, d;
	cin >> a >> b >> c >> d;
	cin >> N;
	num.resize(N);
	s.resize(N);
	cin.ignore();
	for (auto &i : s)getline(cin, i);
	for (auto i : s) {
		string t;
		vector<string>u;
		for (auto j : i) {
			if (j == ':')continue;
			if (j == ' ') {
				if (name.size() == to.size()) {
					mp[t] = M++;
					name.push_back(t);
				}
				else {
					u.push_back(t);
				}
				t.clear();
				continue;
			}
			t.push_back(j);
		}
		u.push_back(t);
		to.push_back(u);
	}
	for (int i = N - 1; i >= 0; i--) {
		for (auto j : to[i]) {
			if (j[0] == '[') {
				int b = 0;
				for (int k = 1; k < j.size() - 1; k++)b += box[j[k]];
				num[i].push_back(b);
			}
			else {
				for (auto k : num[mp[j]]) {
					num[i].push_back(k);
				}
			}
		}
		if (num[i].size() > 200)num[i].resize(201);
	}
	dp[0][0][0][0] = 1;
	if (num[0].size() != a + b + c + d) {
		cout << 0 << endl;
		return 0;
	}
	for (int sum = 0; sum <= num[0].size(); sum++) {
		for (int i = 0; i <= a; i++) {
			for (int j = 0; j <= b && i + j <= sum; j++) {
				for (int k = 0; k <= c && i + j + k <= sum; k++) {
					int l = sum - i - j - k;
					if (l<0 || l>d)continue;
					if ((num[0][sum] >> 0) & 1) {
						dp[i + 1][j][k][l] += dp[i][j][k][l];
						dp[i + 1][j][k][l] %= MOD;
					}
					if ((num[0][sum] >> 1) & 1) {
						dp[i][j + 1][k][l] += dp[i][j][k][l];
						dp[i][j + 1][k][l] %= MOD;
					}
					if ((num[0][sum] >> 2) & 1) {
						dp[i][j][k + 1][l] += dp[i][j][k][l];
						dp[i][j][k + 1][l] %= MOD;
					}
					if ((num[0][sum] >> 3) & 1) {
						dp[i][j][k][l + 1] += dp[i][j][k][l];
						dp[i][j][k][l + 1] %= MOD;
					}
				}
			}
		}
	}
	cout << dp[a][b][c][d] << endl;
}
accuracy: 1
time_ms: 140
memory_kb: 31400
final_rank: 6