#include #include #include #include #include #include using namespace std; #define rep(i,n) for(int i=0; i<(int)(n); i++) using Modint = atcoder::static_modint<998244353>; const int SZ = 50; const int SZZ = SZ * (SZ+1) / 2; int Z(const string& preof, const string& sufof){ int x = min(preof.size(), sufof.size()); auto z = atcoder::z_algorithm(preof.substr(0, x) + sufof.substr(sufof.size() - x)); for(int i=x; i>=1; i--) if(z[z.size()-i] >= i) return i; return 0; } string T; int t; int T6L[SZ+1]={}, T6R[SZ+1]={}; int T5[SZ+1][SZ+1]={}; string TPRE[SZ+1]; string TSUF[SZ+1]; vector substrs; int T4[SZZ][SZZ]={}; int T3L[SZZ]={}, T3R[SZZ]={}; int T2L[SZZ][SZ]={}, T2R[SZZ][SZ]={}; int T1[SZ][SZ]={}; void precalc(){ t = T.size(); rep(i,t+1) TPRE[i] = T.substr(0, i); rep(i,t+1) TSUF[i] = T.substr(t-i); rep(i,t+1) T6L[i] = i ? Z(TSUF[i].substr(0,i-1), T) : 0; rep(i,t+1) T6R[i] = i ? Z(T, TPRE[i].substr(1)) : 0; auto sa = atcoder::suffix_array(T); auto lcp = atcoder::lcp_array(T, sa); rep(i,t+1) rep(j,t+1) T5[i][j] = -1; rep(i,t){ int k = i ? lcp[i-1] : 0; for(int j=1; j<=t-sa[i] && j=t) cnt++; return Node{ Z(s,TSUF[t-1]), Z(TPRE[t-1],s), Modint::raw(cnt) }; } Node mergeNode(Node l, Node r){ if(l.r >= 0){ if(r.r >= 0) return { l.l, r.r, l.c + r.c + Modint::raw(T1[l.r][r.l]) }; return { l.l, T2R[r.l][l.r], l.c + Modint::raw(T1[l.r][T3L[r.l]]) }; } if(r.r < 0){ int nx = T4[l.l][r.l]; if(nx >= 0) return { nx, -1, Modint() }; int lr = T3R[l.r], rl = T3L[r.l]; return { T2L[l.l][rl], T2R[r.l][lr], Modint::raw(T1[lr][rl]) }; } return { T2L[l.l][r.l], r.r, r.c + Modint::raw(T1[T3R[l.l]][r.l]) }; } int main() { int N; cin >> N; cin >> T; precalc(); vector X(N); rep(i,N){ string s; cin >> s; if(s == "~"){ int j,k; cin >> j >> k; X[i] = mergeNode(X[j-1], X[k-1]); } else{ X[i] = createNode(s); } } cout << X[N-1].c.val() << '\n'; return 0; }