Problem:
Tree Generators
One of the problems in the International Parsing Contest caught your attention.
Two expressions are given as input, each representing a procedure to generate a single tree. The gen eration procedure is randomized, meaning different trees may be generated each time the procedure is  performed. You are asked to count the number of trees that can possibly be generated from
both
of the expressions.
The syntax of an expression is as follows.
$E$ $::=$ '
1
' $|$ '
(
' $E$ $E$ '
)
'
A tree is generated from an expression according to the following procedure.
The expression 1 generates a tree with a single vertex labeled 1.
For two expressions $E_1$ and $E_2$, an expression ($E_1 E_2$) generates a tree as follows:
A tree $T_1$ is generated from $E_1$ with $n_1$ vertices, and $T_2$ from $E_2$ with $n_2$ vertices.
Then, the labels of all vertices in $T_2$ are incremented by $n_1$.
After that, two vertices, one from $T_1$ and the other from $T_2$, are randomly chosen. Adding an edge connecting them forms a single tree with vertices labeled 1 through ($n_1 + n_2$), which is the tree generated by ($E_1 E_2$).
For example, the expression
(11)
can generate only the leftmost tree in Figure D.1, while
(1(11))
can generate the remaining two trees.
Figure D.1. Trees generated from the two expressions,
(11)
and
(1(11))
The same tree may be generated from different expressions. The middle tree can also be generated from
((11)1)
.
For given two expressions of the same length, count the number of trees that can be generated from both of the expressions. Note that the trees generated from them always have the same number of vertices. Two trees are considered different if there exist two indices $i$ and $j$ such that vertices labeled $i$ and $j$ are connected by an edge in one tree but not in the other.
Input
The input consists of two lines, each containing an expression string. The two strings have the same length, between $1$ and $7 \times 10^5$, inclusive, and follow the syntax given above.
Output
Output the number of trees that can be generated from both expressions modulo 998244353.
Sample Input 1
((1(11))1)
((11)(11))
Sample Output 1
1
Sample Input 2
(1(11))
(1(11))
Sample Output 2
2
Sample Input 3
(((11)(11))((11)1))
((1(11))(1(1(11))))
Sample Output 3
3
Sample Input 4
((11)(((1(11))1)((11)1)))
(1(((11)((11)(11)))(11)))
Sample Output 4
4
For Sample Input 1, the trees that can be generated from the two expressions are shown in Figure D.2. The top six trees correspond to the first expression and the bottom four correspond to the second. Only the leftmost tree in each row can be generated from both.
Figure D.2. Illustration of Sample Input 1

Submitted solutions:

code_snippet: //https://zenn.dev/antyuntyun/articles/atcoder-cpp-template
#include <iostream>
#include <bits/stdc++.h>
// #include <atcoder/all>
using namespace std;
// using namespace atcoder;

// clang-format off
// cin cout の結びつけ解除, stdioと同期しない(入出力非同期化)
// cとstdの入出力を混在させるとバグるので注意
struct Fast {Fast() {std::cin.tie(0); ios::sync_with_stdio(false);}} fast;

/* alias */
using ull = unsigned long long;
using ll = long long;

/* vector */
template <class T> using vc = std::vector<T>;
template <class T> using vvc = std::vector<vc<T>>;
template <class T> using vvvc = std::vector<vvc<T>>;
template <class T> using vvvvc = std::vector<vvvc<T>>;

/* define short */
#define pb push_back
#define mp make_pair
#define all(obj) (obj).begin(), (obj).end()
#define YesNo(bool) if(bool){cout<<"Yes"<<endl;}else{cout<<"No"<<endl;}

/* REP macro */
#define reps(i, a, n) for (ll i = (a); i < (ll)(n); ++i)
#define rep(i, n) reps(i, 0, n)
#define rrep(i, n) reps(i, 1, n + 1)
#define repd(i,n) for(ll i=n-1;i>=0;i--)
#define rrepd(i,n) for(ll i=n;i>=1;i--)

/* debug */
// 標準エラー出力を含む提出はrejectされる場合もあるので注意
#define debug(x) cerr << "\033[33m(line:" << __LINE__ << ") " << #x << ": " << x << "\033[m" << endl;

/* func */
inline int in_int() {int x; cin >> x; return x;}
inline ll in_ll() {ll x; cin >> x; return x;}
inline string in_str() {string x; cin >> x; return x;}
template <typename T> inline void print(const vector<T>& v, string s = " ")
    {rep(i, v.size()) cout << v[i] << (i != (ll)v.size() - 1 ? s : "\n");}
template <typename T, typename S> inline void print(const pair<T, S>& p)
    {cout << p.first << " " << p.second << endl;}
template <typename T> inline void print(const T& x) {cout << x << "\n";}
template <typename T, typename S> inline void print(const vector<pair<T, S>>& v)
    {for (auto&& p : v) print(p);}
// 第一引数と第二引数を比較し、第一引数(a)をより大きい/小さい値に上書き
template <typename T> inline bool chmin(T& a, const T& b) {bool compare = a > b; if (a > b) a = b; return compare;}
template <typename T> inline bool chmax(T& a, const T& b) {bool compare = a < b; if (a < b) a = b; return compare;}

// https://algo-logic.info/run-length/
/* encode: ランレングス圧縮を行う
*/
vector<pair<char, int>> encode(const string& str) {
    int n = (int)str.size();
    vector<pair<char, int>> ret;
    for (int l = 0; l < n;) {
        int r = l + 1;
        for (; r < n && str[l] == str[r]; r++) {};
        ret.push_back({str[l], r - l});
        l = r;
    }
    return ret;
}

/* decode: ランレングス圧縮の復元を行う
*/
string decode(const vector<pair<char, int>>& code) {
    string ret = "";
    for (auto p : code) {
        for (int i = 0; i < p.second; i++) {
            ret.push_back(p.first);
        }
    }
    return ret;
}

// ２次元ベクトルにおける、偏角によるソートの実装
//ベクトル用のclass
class Vector2D {
public:
    ll x;
    ll y;
    Vector2D(ll x=0,ll y=0):x(x),y(y){}
};


//二つのベクトルのx軸との偏角を行列式を用いて比較する関数
bool IsLarge(Vector2D a,Vector2D b){
    // 外積を用いて偏角を比較
    // a × b = a.x * b.y - a.y * b.x
    // 正の場合、aの偏角 < bの偏角
    // 負の場合、aの偏角 > bの偏角
    
    // まず象限で比較
    auto getQuadrant = [](const Vector2D& v) -> int {
        if (v.x > 0 && v.y >= 0) return 1;  // 第1象限
        if (v.x <= 0 && v.y > 0) return 2;  // 第2象限
        if (v.x < 0 && v.y <= 0) return 3;  // 第3象限
        if (v.x >= 0 && v.y < 0) return 4;  // 第4象限
        return 0; // 原点
    };
    
    int quadA = getQuadrant(a);
    int quadB = getQuadrant(b);
    
    if (quadA != quadB) {
        return quadA < quadB;
    }
    
    // 同じ象限内では外積で比較
    ll cross = a.x * b.y - a.y * b.x;
    return cross > 0;  // aの偏角 < bの偏角の場合true
}

bool IsSame(Vector2D a,Vector2D b){
    ll cross = a.x * b.y - a.y * b.x;
    return cross == 0;  // aの偏角 < bの偏角の場合true
}

//AがBより右下かどうかでソートするための関数
bool IsRight(Vector2D a,Vector2D b){
    if(a.x != b.x){
        return a.x < b.x; 
    }
    return a.y < b.y; 
}

pair<vc<ll>,vc<ll>> purse(string S){
    ll N = S.size();
    vc<ll> ids;
    rep(i,N){
        if(S[i]=='1'){
            ids.pb(i);
        }
    }
    ll M = ids.size();
    vc<ll> left(M,-1), right(M,-1);
    vc<pair<ll,ll>> stc;
    rep(i,N){
        if(S[i]=='1'){
            ll id = lower_bound(all(ids),i)-ids.begin();
            stc.emplace_back(id, id+1);
        }else if(S[i]==')'){
            auto [m1,r] = stc.back();
            stc.pop_back();
            auto [l,m2] = stc.back();
            stc.pop_back();
            stc.emplace_back(l,r);
            // debug(l);
            // debug(r);
            // debug(m1);
            left[m1]=l;
            right[m1]=r;
        }
    }
    return mp(left,right);
}

ll mod = 998244353;

int main() {
    string S,T;
    cin >> S >> T;
    auto [sl,sr] = purse(S);
    auto [tl,tr] = purse(T);
    // print(sl);
    // print(sr);
    // print(tl);
    // print(tr);
    ll ans = 1, N = sl.size();
    reps(i,1,N){
        ll rMin = min(sr[i]-i,tr[i]-i);
        ll lMin = min(i-sl[i],i-tl[i]);
        ll prd = rMin * lMin % mod;
        ans = ans * prd % mod;
        // debug(ans);
    }
    cout << ans << endl;
    return 0;
}
accuracy: 1
time_ms: 30
memory_kb: 22384
final_rank: 10

code_snippet: #include<bits/stdc++.h>
#define rep(i,n) for(ll i=0;i<(ll)(n);i++)
#define all(x) x.begin(),x.end()
using namespace std;
using ll=long long;
using P=pair<ll,ll>;

const ll INF=1001001001001001001;
const ll mod=998244353;

pair<vector<ll>,vector<ll>> f(string s){
    vector<ll> id;
    rep(i,s.size())if(s[i]=='1')id.push_back(i);

    ll n=id.size();
    vector<ll> L(n,-1),R(n,-1);
    vector<P> st;

    rep(i,s.size()){
        if(s[i]=='1'){
            ll idx=lower_bound(all(id),i)-id.begin();
            st.push_back({idx,idx+1});
        }
        else if(s[i]==')'){
            auto[j,r]=st.back();
            st.pop_back();
            auto[l,jj]=st.back();
            st.pop_back();
            st.push_back({l,r});
            L[j]=l;
            R[j]=r;
        }
    }
    return {L,R};
}

int main(){
    string s,t;cin>>s>>t;
    auto[ls,rs]=f(s);
    auto[lt,rt]=f(t);

    //rep(i,ls.size()){
    //    cout<<ls[i]<<" "<<rs[i]<<endl;
    //}
    //rep(i,ls.size()){
    //    cout<<lt[i]<<" "<<rt[i]<<endl;
    //}

    ll ans=1;
    for(int i=1;i<ls.size();i++){
        ll lp=i-max(ls[i],lt[i]);
        ll rp=min(rs[i],rt[i])-i;
        ans=(ans*((lp*rp)%mod))%mod;
    }

    cout<<ans<<endl;
}
accuracy: 1
time_ms: 40
memory_kb: 22300
final_rank: 13

code_snippet: #include<bits/stdc++.h>
#define rep(i,n) for(ll i=0;i<(ll)(n);i++)
#define all(x) x.begin(),x.end()
using namespace std;
using ll=long long;
using P=pair<ll,ll>;

const ll INF=1001001001001001001;
const ll mod=998244353;

pair<vector<ll>,vector<ll>> f(string s){
    vector<ll> id;
    rep(i,s.size())if(s[i]=='1')id.push_back(i);

    ll n=id.size();
    vector<ll> L(n,-1),R(n,-1);
    vector<P> st;

    rep(i,s.size()){
        if(s[i]=='1'){
            ll idx=lower_bound(all(id),i)-id.begin();
            st.push_back({idx,idx+1});
        }
        else if(s[i]==')'){
            auto[j,r]=st.back();
            st.pop_back();
            auto[l,jj]=st.back();
            st.pop_back();
            st.push_back({l,r});
            L[j]=l;
            R[j]=r;
        }
    }
    return {L,R};
}

int main(){
    string s,t;cin>>s>>t;
    auto[ls,rs]=f(s);
    auto[lt,rt]=f(t);

    //rep(i,ls.size()){
    //    cout<<ls[i]<<" "<<rs[i]<<endl;
    //}
    //rep(i,ls.size()){
    //    cout<<lt[i]<<" "<<rt[i]<<endl;
    //}

    ll ans=1;
    for(int i=1;i<ls.size();i++){
        ll lp=i-max(ls[i],lt[i]);
        ll rp=min(rs[i],rt[i])-i;
        ans=(ans*((lp*rp))%mod)%mod;
    }

    cout<<ans<<endl;
}
accuracy: 0.6444444444444445
time_ms: 40
memory_kb: 22152
final_rank: 20

code_snippet: #include<bits/stdc++.h>
#define rep(i,n) for(ll i=0;i<(ll)(n);i++)
#define all(x) x.begin(),x.end()
using namespace std;
using ll=long long;
using P=pair<ll,ll>;

const ll INF=1001001001001001001;
const ll mod=998244353;

pair<vector<ll>,vector<ll>> f(string s){
    vector<ll> id;
    rep(i,s.size())if(s[i]=='1')id.push_back(i);

    ll n=id.size();
    vector<ll> L(n,-1),R(n,-1);
    vector<P> st;

    rep(i,s.size()){
        if(s[i]=='1'){
            ll idx=lower_bound(all(id),i)-id.begin();
            st.push_back({idx,idx+1});
        }
        else if(s[i]==')'){
            auto[j,r]=st.back();
            st.pop_back();
            auto[l,jj]=st.back();
            st.pop_back();
            st.push_back({l,r});
            L[j]=l;
            R[j]=r;
        }
    }
    return {L,R};
}

int main(){
    string s,t;cin>>s>>t;
    auto[ls,rs]=f(s);
    auto[lt,rt]=f(t);

    //rep(i,ls.size()){
    //    cout<<ls[i]<<" "<<rs[i]<<endl;
    //}
    //rep(i,ls.size()){
    //    cout<<lt[i]<<" "<<rt[i]<<endl;
    //}

    ll ans=1;
    for(int i=1;i<ls.size();i++){
        ll lp=i-max(ls[i],lt[i]);
        ll rp=min(rs[i],rt[i])-i;
        ans=(ans*(lp*rp)%mod)%mod;
    }

    cout<<ans<<endl;
}
accuracy: 0.6444444444444445
time_ms: 40
memory_kb: 22144
final_rank: 19

code_snippet: #include<bits/stdc++.h>
using namespace std;
#define rep(i,n) for(int i = 0;i < (n);i++)
#define eb emplace_back
#define si(x) (ll)x.size()
#define all(x) x.begin(),x.end()
#define pll pair<ll,ll>
#define vll vector<ll>
#define inf LLONG_MAX / 3
template<class T> bool chmin(T& a, const T& b){ if(a <= b) return 0; a = b; return 1; }
template<class T> bool chmax(T& a, const T& b){ if(a >= b) return 0; a = b; return 1; }
typedef long long ll;


int main(){
	cin.tie(0);
	ios::sync_with_stdio(0);
	vector<string> s(2);
	rep(i,2)cin>>s[i];
	ll n = 0;
	rep(i,si(s[0]))n += s[0][i] == '1';
	vll L(n,-1),R(n,inf);
	rep(k,2){
		stack<pll> st;
		ll id = 0;
		for(auto &&c: s[k]){
			if(c == ')'){
				auto [m,r] = st.top(); st.pop();
				auto [l,m_] = st.top(); st.pop();
				assert(m == m_);
				chmax(L[m], l);
				chmin(R[m], r);
				st.push({l,r});
			}else if(c == '1'){
				st.push({id, id+1});
				id++;
			}
		}
	}
	const ll mod = 998244353;
	ll ans = 1;
	for(ll i = 1;i < n;i++){
		ans = ans * (R[i] - i) % mod;
		ans = ans * (i - L[i]) % mod;
	}
	cout<<ans<<endl;
}
accuracy: 1
time_ms: 10
memory_kb: 12016
final_rank: 2

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef __int128 lll;
using ull = unsigned long long;
typedef pair<ll,ll> pll;
typedef vector<ll> vll;
typedef vector<pll> vpll;
template<class T> using pqmin = priority_queue<T, vector<T>, greater<T>>;
template<class T> using pqmax = priority_queue<T>;
const ll inf=LLONG_MAX/3;
const ll dx[] = {0, 1, 0, -1, 1, -1, 1, -1};
const ll dy[] = {1, 0, -1, 0, 1, 1, -1, -1};
#define mp make_pair
#define pb push_back
#define eb emplace_back
#define fi first
#define se second
#define all(x) x.begin(),x.end()
#define si(x) ll(x.size())
#define rept(n) for(ll _ovo_=0;_ovo_<n;_ovo_++)
#define rep(i,n) for(ll i=0;i<n;i++)
#define per(i,n) for(ll i=n-1;i>=0;i--)
#define rng(i,l,r) for(ll i=l;i<r;i++)
#define gnr(i,l,r) for(ll i=r-1;i>=l;i--)
#define fore(i, a) for(auto &&i : a)
#define fore2(a, b, v) for(auto &&[a, b] : v)
#define fore3(a, b, c, v) for(auto &&[a, b, c] : v)
template<class T> bool chmin(T& a, const T& b){ if(a <= b) return 0; a = b; return 1; }
template<class T> bool chmax(T& a, const T& b){ if(a >= b) return 0; a = b; return 1; }
template<class T, class U> bool chmin(T& a, const U& b){ return chmin(a, (T)b); }
template<class T, class U> bool chmax(T& a, const U& b){ return chmax(a, (T)b); }
#define LL(...) ll __VA_ARGS__;in(__VA_ARGS__)
#define STR(...) string __VA_ARGS__;in(__VA_ARGS__)
#define CHR(...) char __VA_ARGS__;in(__VA_ARGS__)
#define vec(type,name,...) vector<type>name(__VA_ARGS__)
#define VEC(type,name,size) vector<type>name(size);in(name)
#define VLL(name,size) vector<ll>name(size);in(name)
#define vv(type,name,h,...) vector<vector<type>> name(h,vector<type>(__VA_ARGS__))
#define VV(type,name,h,w) vector<vector<type>> name(h,vector<type>(w));in(name)
#define vvv(type,name,h,w,...) vector<vector<vector<type>>> name(h,vector<vector<type>>(w,vector<type>(__VA_ARGS__)))
#define SUM(...) accumulate(all(__VA_ARGS__),0LL)
template<class T> auto min(const T& a){ return *min_element(all(a)); }
template<class T> auto max(const T& a){ return *max_element(all(a)); }
template<class T, class F = less<>> void sor(T& a, F b = F{}){ sort(all(a), b); }
template<class T> void uniq(T& a){ sor(a); a.erase(unique(all(a)), end(a)); }
template<class T, class F = less<>> map<T,vector<ll> > ivm(vector<T>& a, F b = F{}){ map<T,vector<ll> > ret; rep(i,si(a))ret[a[i]].push_back(i); return ret;}
template<class T, class F = less<>> map<T,ll> ivc(vector<T>& a, F b = F{}){ map<T,ll> ret; rep(i,si(a))ret[a[i]]++; return ret;}
template<class T, class F = less<>> vector<T> ivp(vector<T> a){ vector<ll> ret(si(a)); rep(i,si(a))ret[a[i]] = i; return ret;}
template<class T, class F = less<>> vector<ll> rev(vector<T> a){ reverse(all(a)); return a;}
template<class T, class F = less<>> vector<ll> sortby(vector<T> a, F b = F{}){vector<ll> w = a; sor(w,b); vector<pll> v; rep(i,si(a))v.eb(a[i],i); sor(v); if(w[0] != v[0].first)reverse(all(v)); vector<ll> ret; rep(i,si(v))ret.pb(v[i].second); return ret;}
template<class T, class P> vector<T> filter(vector<T> a,P f){vector<T> ret;rep(i,si(a)){if(f(a[i]))ret.pb(a[i]);}return ret;}
template<class T, class P> vector<ll> filter_id(vector<T> a,P f){vector<ll> ret;rep(i,si(a)){if(f(a[i]))ret.pb(i);}return ret;}
ll monotone_left(function<bool(ll)> f){ll l = -1,r = (ll)1e18 + 1; assert(f(l + 1) >= f(r - 1)); while(l + 1 < r){ll mid = (l + r)>> 1; (f(mid)?l:r) = mid;} return l;}
ll monotone_left(ll l,ll r,function<bool(ll)> f){l--; assert(f(l + 1) >= f(r - 1)); while(l + 1 < r){ll mid = (l + r)>> 1; (f(mid)?l:r) = mid;} return l;}
ll monotone_right(function<bool(ll)> f){ll l = -1,r = (ll)1e18 + 1; assert(f(l + 1) <= f(r - 1)); while(l + 1 < r){ll mid = (l + r)>> 1; (f(mid)?r:l) = mid;} return r;}
ll monotone_right(ll l,ll r,function<bool(ll)> f){l--; assert(f(l + 1) <= f(r - 1)); while(l + 1 < r){ll mid = (l + r)>> 1; (f(mid)?r:l) = mid;} return r;}
double monotone_double_left(double l,double r,function<bool(double)> f){assert(f(l) >= f(r)); rep(_,100){double mid = (l + r) / 2.0; (f(mid)?l:r) = mid;} return l;}
double monotone_double_right(double l,double r,function<bool(double)> f){assert(f(l) <= f(r)); rep(_,100){double mid = (l + r) / 2.0; (f(mid)?l:r) = mid;} return r;}
template<class S> S unimodal_max(ll l,ll r,function<S(ll)> f){while(l + 2 < r){ll m1 = l + (r - l) / 3,m2 = l + (r - l) / 3 * 2; if(f(m1) < f(m2))l = m1; else r = m2;} S ret = f(l); rng(k,l,r + 1)chmax(ret,f(k)); return ret;}
template<class S> S unimodal_min(ll l,ll r,function<S(ll)> f){while(l + 2 < r){ll m1 = l + (r - l) / 3,m2 = l + (r - l) / 3 * 2; if(f(m1) > f(m2))l = m1; else r = m2;} S ret = f(l); rng(k,l,r + 1)chmin(ret,f(k)); return ret;}
vector<pll> neighbor4(ll x,ll y,ll h,ll w){vector<pll> ret;rep(dr,4){ll xx = x + dx[dr],yy = y + dy[dr]; if(0 <= xx && xx < h && 0 <= yy && yy <w)ret.eb(xx,yy);} return ret;};
vector<pll> neighbor8(ll x,ll y,ll h,ll w){vector<pll> ret;rep(dr,8){ll xx = x + dx[dr],yy = y + dy[dr]; if(0 <= xx && xx < h && 0 <= yy && yy <w)ret.eb(xx,yy);} return ret;};

void outb(bool x){cout<<(x?"Yes":"No")<<"\n";}
ll max(int x, ll y) { return max((ll)x, y); }
ll max(ll x, int y) { return max(x, (ll)y); }
int min(int x, ll y) { return min((ll)x, y); }
int min(ll x, int y) { return min(x, (ll)y); }
#define lb(c, x) distance((c).begin(), lower_bound(all(c), (x)))
#define lbg(c, x) distance((c).begin(), lower_bound(all(c), (x), greater{}))
#define ub(c, x) distance((c).begin(), upper_bound(all(c), (x)))
#define ubg(c, x) distance((c).begin(), upper_bound(all(c), (x), greater{}))
ll gcd(ll a,ll b){return (b?gcd(b,a%b):a);}
vector<pll> factor(ull x){ vector<pll> ans; for(ull i = 2; i * i <= x; i++) if(x % i == 0){ ans.push_back({i, 1}); while((x /= i) % i == 0) ans.back().second++; } if(x != 1) ans.push_back({x, 1}); return ans; }
vector<ll> divisor(ull x){ vector<ll> ans; for(ull i = 1; i * i <= x; i++) if(x % i == 0) ans.push_back(i); per(i,ans.size() - (ans.back() * ans.back() == x)) ans.push_back(x / ans[i]); return ans; }
vll prime_table(ll n){vec(ll,isp,n+1,1);vll res;rng(i,2,n+1)if(isp[i]){res.pb(i);for(ll j=i*i;j<=n;j+=i)isp[j]=0;}return res;}
ll powll(lll x,ll y){lll res = 1; while(y){ if(y & 1)res = res * x; x = x * x; y >>= 1;} return res;}
ll powmod(lll x,ll y,lll mod){lll res=1; while(y){ if(y&1)res=res*x%mod; x=x*x%mod; y>>=1;} return res; }
ll modinv(ll a,ll m){ll b=m,u=1,v=0;while(b){ll t=a/b;a-=t*b;swap(a,b);u-=t*v;swap(u,v);}u%=m;if(u<0)u+=m;return u;}

template <class T, class S> pair<T, S> operator-(const pair<T, S> &x) { return pair<T, S>(-x.first, -x.second); }
template <class T, class S> pair<T, S> operator-(const pair<T, S> &x, const pair<T, S> &y) { return pair<T, S>(x.fi - y.fi, x.se - y.se); }
template <class T, class S> pair<T, S> operator+(const pair<T, S> &x, const pair<T, S> &y) { return pair<T, S>(x.fi + y.fi, x.se + y.se); }
template <class T> pair<T, T> operator&(const pair<T, T> &l, const pair<T, T> &r) { return pair<T, T>(max(l.fi, r.fi), min(l.se, r.se)); }
template <class T, class S> pair<T, S> operator+=(pair<T, S> &l, const pair<T, S> &r) { return l = l + r; }
template <class T, class S> pair<T, S> operator-=(pair<T, S> &l, const pair<T, S> &r) { return l = l - r; }
template <class T> bool intersect(const pair<T, T> &l, const pair<T, T> &r) { return (l.se < r.se ? r.fi < l.se : l.fi < r.se); }

template <class T> vector<T> &operator++(vector<T> &v) {
		fore(e, v) e++;
		return v;
}
template <class T> vector<T> operator++(vector<T> &v, int) {
		auto res = v;
		fore(e, v) e++;
		return res;
}
template <class T> vector<T> &operator--(vector<T> &v) {
		fore(e, v) e--;
		return v;
}
template <class T> vector<T> operator--(vector<T> &v, int) {
		auto res = v;
		fore(e, v) e--;
		return res;
}
template <class T> vector<T> &operator+=(vector<T> &l, const vector<T> &r) {
		fore(e, r) l.eb(e);
		return l;
}

template<class... Ts> void in(Ts&... t);
[[maybe_unused]] void print(){}
template<class T, class... Ts> void print(const T& t, const Ts&... ts);
template<class... Ts> void out(const Ts&... ts){ print(ts...); cout << '\n'; }
namespace IO{
#define VOID(a) decltype(void(a))
struct S{ S(){ cin.tie(nullptr)->sync_with_stdio(0); fixed(cout).precision(12); } }S;
template<int I> struct P : P<I-1>{};
template<> struct P<0>{};
template<class T> void i(T& t){ i(t, P<3>{}); }
void i(vector<bool>::reference t, P<3>){ int a; i(a); t = a; }
template<class T> auto i(T& t, P<2>) -> VOID(cin >> t){ cin >> t; }
template<class T> auto i(T& t, P<1>) -> VOID(begin(t)){ for(auto&& x : t) i(x); }
template<class T, size_t... idx> void ituple(T& t, index_sequence<idx...>){ in(get<idx>(t)...); }
template<class T> auto i(T& t, P<0>) -> VOID(tuple_size<T>{}){ ituple(t, make_index_sequence<tuple_size<T>::value>{}); }
template<class T> void o(const T& t){ o(t, P<4>{}); }
template<size_t N> void o(const char (&t)[N], P<4>){ cout << t; }
template<class T, size_t N> void o(const T (&t)[N], P<3>){ o(t[0]); for(size_t i = 1; i < N; i++){ o(' '); o(t[i]); } }
template<class T> auto o(const T& t, P<2>) -> VOID(cout << t){ cout << t; }
template<class T> auto o(const T& t, P<1>) -> VOID(begin(t)){ bool first = 1; for(auto&& x : t) { if(first) first = 0; else o(' '); o(x); } }
template<class T, size_t... idx> void otuple(const T& t, index_sequence<idx...>){ print(get<idx>(t)...); }
template<class T> auto o(T& t, P<0>) -> VOID(tuple_size<T>{}){ otuple(t, make_index_sequence<tuple_size<T>::value>{}); }
#undef VOID
}
#define unpack(a) (void)initializer_list<int>{(a, 0)...}
template<class... Ts> void in(Ts&... t){ unpack(IO::i(t)); }
template<class T, class... Ts> void print(const T& t, const Ts&... ts){ IO::o(t); unpack(IO::o((cout << ' ', ts))); }
#undef unpack

const ll mod = 998244353;
int main(){
	cin.tie(0);
	ios::sync_with_stdio(0);
	vector<string> s(2);
	rep(i,2)cin>>s[i];
	ll n = 0;
	rep(i,si(s[0]))n += s[0][i] == '1';
	vll L(n,-1), R(n,inf);
	rep(k,2){
		stack<pll> st;
		ll i = 0;
		for(auto &&c:s[k]){
			if(c == ')'){
				auto [m, r] = st.top();
				st.pop();
				auto [l, m_] = st.top();
				st.pop();
				assert(m == m_);
				// cout<<l<<" "<<r<<" "<<m<<endl;
				chmax(L[m], l);
				chmin(R[m], r);
				st.push({l,r});
			}else if(c == '1'){
				st.push({i,i + 1});
				// cout<<i<<" "<<i + 1<<endl;
				i++;
			}
		}
	}
	ll ans = 1;
	for(ll i = 1;i < n;i++){
		// cout<<L[i]<<" "<<R[i]<<endl;
		ans = ans * (R[i] - i) % mod * (i - L[i]) % mod;
	}
	cout<<ans<<endl;
}
accuracy: 1
time_ms: 10
memory_kb: 11888
final_rank: 1

code_snippet: #ifdef _DEBUG
#define _GLIBCXX_DEBUG
#endif
#include <bits/stdc++.h>
using namespace std;
#include <atcoder/all>
using namespace atcoder;
// #include <boost/rational.hpp>
// using namespace boost;
// using rat = rational<long long int>;
using mint = modint998244353;
// using mint = modint1000000007;
// using mint = mint;
using ll = long long;
using ld = long double;
using ull = uint64_t;
using pll = pair<ll, ll>;
using vll = vector<ll>;
using vvll = vector<vll>;
using vvvll = vector<vvll>;
using vpll = vector<pll>;
using vvpll = vector<vpll>;
using vm = vector<mint>;
using vvm = vector<vm>;
using vvvm = vector<vvm>;
using vstr = vector<string>;
#define v(T) vector<T>
#define vv(T) vector<vector<T>>
#define vvv(T) vector<vector<vector<T>>>
#define vvvv(T) vector<vector<vector<vector<T>>>>

istream &operator>>(istream &is, mint &a){ll tmp; is >> tmp; a = tmp; return is;}
ostream &operator<<(ostream &os, const mint &a){ os << a.val(); return os; }
string to_string(const __int128_t &a) { if (a == 0) return "0"; string s = ""; __int128_t num = a; bool is_negative = false; if (num < 0) { is_negative = true; num = -num; } while (num > 0) { s += '0' + (num % 10); num /= 10; } if (is_negative) s += '-'; reverse(s.begin(), s.end()); return s; }
istream &operator>>(istream &is, __int128_t &a){ string s; is >> s; a = 0; for(char c : s) { if(isdigit(c)) {a = a*10 + (c - '0'); }  } if(s[0]=='-'){ a *= -1; } return is; }
ostream &operator<<(ostream &os, const __int128_t &a){ os << to_string(a); return os; }
template<class T, class U> istream &operator>>(istream &is, pair<T, U> &p) { is >> p.first >> p.second; return is; }
template<class T, class U> ostream &operator<<(ostream &os, const pair<T, U> &p) { os << p.first << " " << p.second; return os; }
template<class T> istream &operator>>(istream &is, vector<T> &vec){ for(T &e : vec){is >> e;} return is; }
template<class T> ostream &operator<<(ostream &os, const vector<T> &vec) { for(int i = 0; i < (int)vec.size(); i++) { os << vec[i] << (i + 1 != (int)vec.size() ? " " : ""); } return os; }

template <class... T> constexpr auto min (T... a) { return min(initializer_list<common_type_t<T...>>{a...}); }
template <class... T> constexpr auto max (T... a) { return max(initializer_list<common_type_t<T...>>{a...}); }
template<class T> using pqg = priority_queue<T, vector<T>, greater<T>>;
template<class T> T opmin(T x, T y) { return min(x, y); }
template<class T> T einf() { return numeric_limits<T>::max(); }
template<class T> T opmax(T x, T y) { return max(x, y); }
template<class T> T eminf() { return numeric_limits<T>::min(); }
template<class T> T opsum(T x, T y) { return x + y; }
template<class T> T ezero() { return (T)0; }
// #define maxseg(T) segtree<T, [](T x, T y){return max(x, y);}, [](){return (T)(-(1LL << 60));}>
// #define minseg(T) segtree<T, [](T x, T y){return min(x, y);}, [](){return (T)((1LL << 60));}>
// #define sumseg(T) segtree<T, [](T x, T y){return x + y;}, [](){return (T)(0);}>
template<class T> using minseg = segtree<T, opmin<T>, einf<T>>;
template<class T> using maxseg = segtree<T, opmax<T>, eminf<T>>;
template<class T> using sumseg = segtree<T, opsum<T>, ezero<T>>;
// template<class T> struct v : vector<T> { using vector<T> :: vector; };
// template<class T> struct vv : vector<v<T>> { using vector<v<T>> :: vector; };
// template<class T> struct vvv : vector<vv<T>> { using vector<vv<T>> :: vector; };
template<class T> inline bool chmin(T& a, T b) {if(a > b){a = b; return true;} else {return false;}};
template<class T> inline bool chmax(T& a, T b) {if(a < b){a = b; return true;} else {return false;}};
#define rep(i,n) for(ll i = 0; i < (ll)(n); i++)
#define repr(i,n) for(ll i = (ll)(n) - 1; i >= 0; i--)
#define REP(i, l, r) for(ll i = (ll)l; i <= (ll)(r); i++)
#define REPR(i, l, r) for(ll i = (ll)r; i >= (ll)(l); i--)
const ll inf = (1 << 30);
const ll INF = (1LL << 60);
const vector<pair<ll, ll>> DIJ = {{1, 0}, {0, -1}, {-1, 0}, {0, 1}};
void out(){cout<<'\n';}
template<class T, class... Ts> void out(const T& a, const Ts&... b){ cout<<a; (cout<<... << (cout << ' ', b)); cout << '\n';}
void outf(){cout<<endl;}
template<class T, class... Ts> void outf(const T& a, const Ts&... b){ cout<<a; (cout<<... << (cout << ' ', b)); cout << endl;}
template<class T, class U> void outp(pair<T, U> a){ out((a).first, (a).second); }
template<class T, class U> void outpf(pair<T, U> a){ outf((a).first, (a).second); }
template<class T> void outv(T a){rep(i, (a).size()){ cout << (a)[i] << " "; } cout << endl;}
template<class T> void outvL(T a){rep(i, (a).size()){out((a)[i]);} cout << flush; }
// template<class T> void outvv(T a){rep(i, a.size()){ rep(j, a.at(i).size()){cout << a.at(i).at(j) << " "; } cout << endl; }}
// template<class T> void outvp(T a){rep(i, a.size()){ out2(a.at(i).first, a.at(i).second); }}
void setpre(int a){cout << fixed << setprecision(a);}
#define outN out("No")
#define outY out("Yes")
#define outYN(flag) out(flag ? "Yes" : "No")
#define dame(...) {outf(__VA_ARGS__);return 0;}

template<class T> void read(vector<T>& vec){ for(int i = 0; i < (int)vec.size(); i++) { cin >> vec[i]; } }
template<class... T> void read(T&... a){(cin >> ... >> a);}
#define readll(...) ll __VA_ARGS__; read(__VA_ARGS__)
#define readvll(a, n) vector<ll> a(n); read(a)
#define readvt(type, a, n) vector<type> a(n); read(a)
#define readvll2(a, b, n) vector<ll> a(n), b(n); for(int lopi = 0; lopi < (int)(n); lopi++) cin >> (a)[lopi] >> (b)[lopi]
#define readvll3(a, b, c, n) vector<ll> a(n), b(n), c(n); for(int lopi = 0; lopi < (int)(n); lopi++) cin >> (a)[lopi] >> (b)[lopi] >> (c)[lopi]
#define readstr(...) string __VA_ARGS__; read(__VA_ARGS__)
#define readundirG(G, N, M) G = vvll(N); rep(lopi, M) {ll a, b; cin >> a >> b; G[a-1].push_back(b-1); G[b-1].push_back(a-1);}
#define readdirG(G, N, M) G = vvll(N); rep(lopi, M) {ll a, b; cin >> a >> b; G[a-1].push_back(b-1);}
#define readundirwghG(G, N, M) G = vv(pll)(N); rep(lopi, M) {ll a, b, c; cin >> a >> b >> c; G[a-1].emplace_back(b-1,c); G[b-1].emplace_back(a-1, c);}
#define readdirwghG (G, N, M) G = vv(pll)(N); rep(lopi, M) {ll a, b, c; cin >> a >> b >> c; G[a-1].emplace_back(b-1, c);}

#define All(a) (a).begin(), (a).end()
template<class T> inline void sortr(T& a){ sort((a).rbegin(), (a).rend()); }
template<class T> inline vector<int> argsort(T V, bool rev = false){vector<int> res(V.size()); iota(res.begin(), res.end(), 0); sort(res.begin(), res.end(), [&](int x, int y){if(!rev){return V[x] < V[y];}else{return V[x] > V[y];}}); return res;}
template<class T, class U> inline void sort_by_idx(T& V, vector<U>& I){assert(V.size() == I.size()); T tmpv = V; for(int loopi = 0; loopi < (int)I.size(); loopi++){V[loopi] = tmpv[I.at(loopi)];}}
template<class T, class U> inline void sortp(vector<T>& v1, vector<U>& v2, bool rev1 = false, int rev2 = false){assert(v1.size() == v2.size()); vector<int> I(v1.size()); iota(I.begin(), I.end(), 0); sort(I.begin(), I.end(), [&](const int x, const int y){if(v1[x] != v1[y]){return (bool)(rev1 ^ (v1[x] < v1[y]));}else{if(v2[x]==v2[y]){return false;} return (bool)(rev2 ^ (v2[x] < v2[y]));}}); sort_by_idx(v1, I); sort_by_idx(v2, I);}
template<class T> T POW(T x, ll n) {T ret = 1; while(n > 0){if(n & 1) ret *= x; x *= x; n >>= 1;} return ret;}
ll powll(ll x, ll n){ll ret = 1; while(n > 0){if(n & 1) ret *= x; x *= x; n >>= 1;} return ret;}
inline ll divceil(ll x, ll y) { if(x >= 0) {return(x / y + (ll)(x % y != 0)); } else { return -((-x) / y); } }
inline ll divfloor(ll x, ll y) { if(x >= 0) { return x/y; } else { return -((-x)/y + (ll)((-x) % y != 0)); } }
inline bool inLR(ll x, ll L, ll R){ return (L <= x && x < R); }
inline bool inRect(ll pos_x, ll pos_y, ll rect_H, ll rect_W, ll rect_h = 0, ll rect_w = 0){ return (rect_h <= pos_x && pos_x < rect_H && rect_w <= pos_y && pos_y < rect_W); }

template<class T> vector<T> &operator++(vector<T> &v) {for(auto &e : v){e++;} return v;}
template<class T> vector<T> operator++(vector<T> &v, signed) {auto res=v; for(auto &e : v){e++;} return res;}
template<class T> vector<T> &operator--(vector<T> &v) {for(auto &e : v){e--;} return v;}
template<class T> vector<T> operator--(vector<T> &v, signed) {auto res=v; for(auto &e : v){e--;} return res;}
template<class T> vector<T> operator+(const vector<T> &x, const vector<T> &y) { assert(x.size() == y.size()); vector<T> ret(x.size()); for(int i = 0; i < (int)x.size(); i++) {ret[i] = x[i] + y[i];} return ret; }
template<class T> vector<T> operator-(const vector<T> &x, const vector<T> &y) { assert(x.size() == y.size()); vector<T> ret(x.size()); for(int i = 0; i < (int)x.size(); i++) {ret[i] = x[i] - y[i];} return ret; } 

template<class T, class U> pair<T, U> operator+(const pair<T, U> &x, const pair<T, U> &y) { return make_pair(x.first + y.first, x.second + y.second); }
template<class T, class U> pair<T, U> operator-(const pair<T, U> &x, const pair<T, U> &y) { return make_pair(x.first - y.first, x.second - y.second); }
template<class T, class U> void operator+=(pair<T, U> &x, pair<T, U> &y) { x = x + y; }
template<class T, class U> void operator-=(pair<T, U> &x, pair<T, U> &y) { x = x - y; }

template<class T> size_t HashCombine(const size_t seed,const T &v){ return seed^(std::hash<T>()(v)+0x9e3779b9+(seed<<6)+(seed>>2)); }
template<class T,class S> struct std::hash<std::pair<T,S>>{ size_t operator()(const std::pair<T,S> &keyval) const noexcept { return HashCombine(std::hash<T>()(keyval.first), keyval.second); } };
template<class T> struct std::hash<std::vector<T>>{ size_t operator()(const std::vector<T> &keyval) const noexcept { size_t s=0; for (auto&& v: keyval) s=HashCombine(s,v); return s; } };
template<int N> struct HashTupleCore{ template<class Tuple> size_t operator()(const Tuple &keyval) const noexcept{ size_t s=HashTupleCore<N-1>()(keyval); return HashCombine(s,std::get<N-1>(keyval)); } };
template <> struct HashTupleCore<0>{ template<class Tuple> size_t operator()(const Tuple &keyval) const noexcept{ return 0; } };
template<class... Args> struct std::hash<std::tuple<Args...>>{ size_t operator()(const tuple<Args...> &keyval) const noexcept { return HashTupleCore<tuple_size<tuple<Args...>>::value>()(keyval); } };

int main()
{
    std::cin.tie(nullptr), std::ios_base::sync_with_stdio(false);
    readstr(S1, S2);
    auto rng = [&](string &S)
    {
        vector<tuple<ll, ll, ll>> tmp;
        ll idx = 0;
        function<void(ll&)> dfs = [&](ll &p)
        {
            if(S[p] == '1')
            {
                idx++;
                p++;
                return;
            }
            if(S[p] == '(')
            {
                p++;
                ll l = idx;
                dfs(p);
                ll m = idx;
                dfs(p);
                ll r = idx;
                p++;
                tmp.emplace_back(l, m, r);
            }
            return;
        };
        ll p =0;
        dfs(p);
        vpll LR(idx, {-1, -1});
        for(auto [l, m, r] : tmp) LR[m] = {l, r};
        return LR;
    };
    auto LR1 = rng(S1);
    auto LR2 = rng(S2);
    mint ans = 1;
    REP(i, 1, LR1.size() - 1)
    {
        auto [l1, r1] = LR1[i];
        auto [l2, r2] = LR2[i];
        ans *= (i - max(l1, l2))*(min(r1, r2) - i);
    }
    out(ans);
}
accuracy: 1
time_ms: 10
memory_kb: 39060
final_rank: 9

code_snippet: // AOJ #1458 Tree Generators
// // 2025.5.3

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int MOD = 998244353;

int parse(const string &s, vector<int> &a, vector<int> &c) {
    int m = s.size();
    vector<int> L, R;
    L.reserve(m);
    R.reserve(m);
    stack<int> st;
    int nleaf = 0, nid = 0;
    for (char ch : s) {
        if (ch == '1') {
            L.push_back(nleaf);
            R.push_back(nleaf);
            st.push(nid++);
            ++nleaf;
        } else if (ch == '(') {
            st.push(-1);
        } else if (ch == ')') {
            int r_id = st.top(); st.pop();
            int l_id = st.top(); st.pop();
            st.pop();
            int b = R[l_id];
            int i = b + 1;
            a[i] = L[l_id] + 1;
            c[i] = R[r_id] + 1;
            L.push_back(L[l_id]);
            R.push_back(R[r_id]);
            st.push(nid++);
        }
    }
    return nleaf;
}

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

    string s, t;
    getline(cin, s);
    getline(cin, t);

    int maxn = (s.size() + 1) / 2;
    vector<int> a1(maxn+1), c1(maxn+1), a2(maxn+1), c2(maxn+1);

    int n1 = parse(s, a1, c1);
    int n2 = parse(t, a2, c2);
    int n = n1;

    ll ans = 1;
    for (int i = 1; i <= n - 1; ++i) {
        int L = max(a1[i], a2[i]);
        int R = min(c1[i], c2[i]);
        if (L > i || R < i+1) {
            ans = 0;
            break;
        }
        ll j_cnt = i - L + 1;
        ll k_cnt = R - i;
        ll ways = (j_cnt * k_cnt) % MOD;
        ans = (ans * ways) % MOD;
    }
    cout << ans << endl;
    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 16124
final_rank: 4

code_snippet: #include <bits/stdc++.h>
using namespace std;
#if __has_include(<atcoder/all>)
#include <atcoder/all>
using namespace atcoder;
#endif
using ll = long long;
using ld = long double;
using ull = unsigned long long;
#define endl "\n"
typedef pair<int, int> Pii;
#define REP(i, n) for (int i = 0; i < (n); ++i)
#define REP3(i, m, n) for (int i = (m); (i) < int(n); ++ (i))
#define rep(i,a,b) for(int i=(int)(a);i<(int)(b);i++)
#define ALL(x) begin(x), end(x)
#define rrep(i,a,b) for(int i=a;i>=b;i--)
#define fore(i,a) for(auto &i:a)
#define all(s) (s).begin(),(s).end()
#define drep2(i, m, n) for (int i = (m)-1; i >= (n); --i)
#define drep(i, n) drep2(i, n, 0)
#define rever(vec) reverse(vec.begin(), vec.end())
#define sor(vec) sort(vec.begin(), vec.end())
#define fi first
#define FOR_(n) for (ll _ = 0; (_) < (ll)(n); ++(_))
#define FOR(i, n) for (ll i = 0; (i) < (ll)(n); ++(i))
#define se second
#define pb push_back
#define P pair<ll,ll>
#define PQminll priority_queue<ll, vector<ll>, greater<ll>>
#define PQmaxll priority_queue<ll,vector<ll>,less<ll>>
#define PQminP priority_queue<P, vector<P>, greater<P>>
#define PQmaxP priority_queue<P,vector<P>,less<P>>
#define NP next_permutation
#define die(a) {cout<<a<<endl;return 0;}
#define dier(a) {return a;}
//const ll mod = 1000000009;
const ll mod = 998244353;
//const ll mod = 1000000007;
const ll inf = 4000000000000000000ll;
const ld eps = ld(0.00000000001);
static const long double pi = 3.141592653589793;
template<class T>void vcin(vector<T> &n){for(int i=0;i<int(n.size());i++) cin>>n[i];}
template<class T,class K>void vcin(vector<T> &n,vector<K> &m){for(int i=0;i<int(n.size());i++) cin>>n[i]>>m[i];}
template<class T>void vcout(vector<T> &n){for(int i=0;i<int(n.size());i++){cout<<n[i]<<" ";}cout<<endl;}
template<class T>void vcin(vector<vector<T>> &n){for(int i=0;i<int(n.size());i++){for(int j=0;j<int(n[i].size());j++){cin>>n[i][j];}}}
template<class T>void vcout(vector<vector<T>> &n){for(int i=0;i<int(n.size());i++){for(int j=0;j<int(n[i].size());j++){cout<<n[i][j]<<" ";}cout<<endl;}cout<<endl;}
void yes(bool a){cout<<(a?"yes":"no")<<endl;}
void YES(bool a){cout<<(a?"YES":"NO")<<endl;}
void Yes(bool a){cout<<(a?"Yes":"No")<<endl;}
void possible(bool a){ cout<<(a?"possible":"impossible")<<endl; }
void Possible(bool a){ cout<<(a?"Possible":"Impossible")<<endl; }
void POSSIBLE(bool a){ cout<<(a?"POSSIBLE":"IMPOSSIBLE")<<endl; }
#define FOR_R(i, n) for (ll i = (ll)(n)-1; (i) >= 0; --(i))
template<class T>auto min(const T& a){ return *min_element(all(a)); }
//template<class T>auto max(const T& a){ return *max_element(all(a)); }
template<class T,class F>void print(pair<T,F> a){cout<<a.fi<<" "<<a.se<<endl;}
template<class T>bool chmax(T &a,const T b) { if (a<b) { a=b; return 1; } return 0;}
template<class T>bool chmin(T &a,const T b) { if (b<a) { a=b; return 1; } return 0;}
template<class T> void ifmin(T t,T u){if(t>u){cout<<-1<<endl;}else{cout<<t<<endl;}}
template<class T> void ifmax(T t,T u){if(t>u){cout<<-1<<endl;}else{cout<<t<<endl;}}
ll fastgcd(ll u,ll v){ll shl=0;while(u&&v&&u!=v){bool eu=!(u&1);bool ev=!(v&1);if(eu&&ev){++shl;u>>=1;v>>=1;}else if(eu&&!ev){u>>=1;}else if(!eu&&ev){v>>=1;}else if(u>=v){u=(u-v)>>1;}else{ll tmp=u;u=(v-u)>>1;v=tmp;}}return !u?v<<shl:u<<shl;}
ll modPow(ll a, ll n, ll mod) { if(mod==1) return 0;ll ret = 1; ll p = a % mod; while (n) { if (n & 1) ret = ret * p % mod; p = p * p % mod; n >>= 1; } return ret; }
vector<ll> divisor(ll x){ vector<ll> ans; for(ll i = 1; i * i <= x; i++){ if(x % i == 0) {ans.push_back(i); if(i*i!=x){ ans.push_back(x / ans[i]);}}}sor(ans); return ans; }
ll pop(ll x){return __builtin_popcountll(x);}
ll poplong(ll x){ll y=-1;while(x){x/=2;y++;}return y;}
P hyou(P a){ll x=fastgcd(abs(a.fi),abs(a.se));a.fi/=x;a.se/=x;if(a.se<0){a.fi*=-1;a.se*=-1;}return a;}
P Pplus(P a,P b){ return hyou({a.fi*b.se+b.fi*a.se,a.se*b.se});}
P Ptimes(P a,ll b){ return hyou({a.fi*b,a.se});}
P Ptimes(P a,P b){ return hyou({a.fi*b.fi,a.se*b.se});}
P Pminus(P a,P b){ return hyou({a.fi*b.se-b.fi*a.se,a.se*b.se});}
P Pgyaku(P a){ return hyou({a.se,a.fi});}
 
void cincout(){
  ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
  cout<< fixed << setprecision(15);
}

int main(){
  cincout();
  string s,t;
  cin>>s>>t;
  ll n=s.size()/3+1;
  vector<ll> l(n-1,-inf),r(n-1,inf);
  {
    vector<P> v;
    ll t=0;
    for(auto e:s){
      if(e=='(') continue;
      if(e=='1'){
        v.pb({t,t});
        t++;
        continue;
      }
      if(e==')'){
        P y=v.back();
        v.pop_back();
        P x=v.back();
        v.pop_back();
        chmax(l[x.se],x.fi);
        chmin(r[x.se],y.se);
        v.pb({x.fi,y.se});
      }
    }
  }
  swap(s,t);
  {
    vector<P> v;
    ll t=0;
    for(auto e:s){
      if(e=='(') continue;
      if(e=='1'){
        v.pb({t,t});
        t++;
        continue;
      }
      if(e==')'){
        P y=v.back();
        v.pop_back();
        P x=v.back();
        v.pop_back();
        chmax(l[x.se],x.fi);
        chmin(r[x.se],y.se);
        v.pb({x.fi,y.se});
      }
    }
  }
  ll ans=1;
  for(int i=0;i<n-1;i++){
    ans*=i-l[i]+1;
    ans%=mod;
    ans*=r[i]-i;
    ans%=mod;
  }
  cout<<ans<<endl;
}
accuracy: 1
time_ms: 10
memory_kb: 15672
final_rank: 3

code_snippet: #ifdef NACHIA
#define _GLIBCXX_DEBUG
#endif
#include <iostream>
#include <vector>
#include <algorithm>
#include <utility>
using namespace std;
#define rep(i,n) for(int i=0; i<int(n); i++)
using i64 = long long;
template<class T> void chmin(T& l, const T& r){ if(r < l) l = r; }
template<class T> void chmax(T& l, const T& r){ if(l < r) l = r; }


struct Case {
    vector<pair<int,int>> res;
    int K;
    string X;
    int P;
    vector<int> buf;
    Case(){ K = 0; P = 0; }
    void read(){
        //cout << "read " << P << " " << K << endl;
        if(X[P] == '1'){ K++; P++; return; }
        buf.push_back(K);
        P++; read();
        res.push_back({ buf.back(), -1 });
        buf.back() = res.size() - 1;
        read(); P++;
        res[buf.back()].second = K;
        buf.pop_back();
    }
};

const int MOD = 998244353;

void testcase(){
    Case AS; cin >> AS.X; AS.read();
    Case AT; cin >> AT.X; AT.read();
    int N = AS.K;
    i64 ans = 1;
    rep(i,N-1){
        int f = max(AS.res[i].first, AT.res[i].first);
        int g = min(AS.res[i].second, AT.res[i].second);
        //cout << "f = " << f << " , g = " << g << endl;
        ans = ans * (i + 1 - f) % MOD;
        ans = ans * (g - i - 1) % MOD;
    }
    cout << ans << "\n";
}

int main(){
    #ifdef NACHIA
    rep(t,4){
        testcase();
        cout << string(10, '-') << endl;
    }
    #else
    testcase();
    #endif
    return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 20092
final_rank: 7

code_snippet: #include <bits/stdc++.h>
using namespace std;
const int MOD = 998244353;

// 各隙間の左側区間の左端と、右側区間の右端を求めていく
pair<vector<long long>, vector<long long>> parse(const string &S) {
    vector<int> oneids;
    for (int i = 0; i < S.size(); i++) if (S[i] == '1') oneids.emplace_back(i);
    vector<long long> left(oneids.size(), -1), right(oneids.size(), -1);

    vector<pair<int,int>> stk;  // 頂点区間を格納するスタック
    for (int i = 0; i < S.size(); i++) {
        if (S[i] == '1') {
            int id = lower_bound(oneids.begin(), oneids.end(), i) - oneids.begin();
            stk.emplace_back(id, id + 1);  // 単独の頂点からなる区間をスタックに挿入
        } else if (S[i] == ')') {
            auto [m, r] = stk.back();  // 隙間 m の、左側区間
            stk.pop_back();
            auto [l, m2] = stk.back();  // 隙間 m の、右側の区間（m = m2 である）
            stk.pop_back();
            stk.emplace_back(l, r);
            left[m] = l, right[m] = r;  // 隙間 m の左側区間の左端は l、右側区間の右端は r
        }
    }
    return make_pair(left, right);
}

int main() {
    string S, T;
    cin >> S >> T;

    auto [ls, rs] = parse(S);
    auto [lt, rt] = parse(T);
    long long res = 1;
    for (long long i = 1; i < ls.size(); i++) {
        long long lnum = i - max(ls[i], lt[i]), rnum = min(rs[i], rt[i]) - i;
        long long mul = lnum * rnum % MOD;
        res = res * mul % MOD;
    }
    cout << res << endl;
}
accuracy: 1
time_ms: 50
memory_kb: 20204
final_rank: 14

code_snippet: #include <bits/stdc++.h>
using namespace std;
const int MOD = 998244353;


#define DEBUG 1
#define COUT(x) if (DEBUG) cout << #x << " = " << (x) << " (L" << __LINE__ << ")" << endl
template<class T1, class T2> ostream& operator << (ostream &s, pair<T1,T2> P)
{ return s << '<' << P.first << ", " << P.second << '>'; }
template<class T> ostream& operator << (ostream &s, vector<T> P)
{ for (int i = 0; i < P.size(); ++i) { if (i > 0) { s << " "; } s << P[i]; } return s; }
template<class T> ostream& operator << (ostream &s, deque<T> P)
{ for (int i = 0; i < P.size(); ++i) { if (i > 0) { s << " "; } s << P[i]; } return s; }
template<class T> ostream& operator << (ostream &s, vector<vector<T> > P)
{ for (int i = 0; i < P.size(); ++i) { s << endl << P[i]; } return s << endl; }
template<class T> ostream& operator << (ostream &s, set<T> P)
{ for (auto it : P) { s << "<" << it << "> "; } return s; }
template<class T> ostream& operator << (ostream &s, multiset<T> P)
{ for (auto it : P) { s << "<" << it << "> "; } return s; }
template<class T1, class T2> ostream& operator << (ostream &s, map<T1,T2> P)
{ for (auto it : P) { s << "<" << it.first << "->" << it.second << "> "; } return s; }




pair<vector<long long>, vector<long long>> parse(const string &S) {
    vector<int> oneids;
    for (int i = 0; i < S.size(); i++) if (S[i] == '1') oneids.emplace_back(i);
    vector<long long> left(oneids.size()+1, -1), right(oneids.size()+1, -1);
    vector<pair<int,int>> stk;
    for (int i = 0; i < S.size(); i++) {
        if (S[i] == '1') {
            int id = lower_bound(oneids.begin(), oneids.end(), i) - oneids.begin();
            stk.emplace_back(id, id + 1);
        } else if (S[i] == ')') {
            auto [m, r] = stk.back();
            stk.pop_back();
            auto [l, m2] = stk.back();
            stk.pop_back();
            stk.emplace_back(l, r);
            left[m] = l, right[m] = r;
        }
    }
    return make_pair(left, right);
}

int main() {
    string S, T;
    cin >> S >> T;

    auto [ls, rs] = parse(S);
    auto [lt, rt] = parse(T);
    //COUT(ls); COUT(rs); COUT(lt); COUT(rt);
    long long res = 1;
    for (long long i = 1; i < ls.size()-1; i++) {
        long long l = i - max(ls[i], lt[i]), r = min(rs[i], rt[i]) - i;
        long long mul = l * r % MOD;
        res = res * mul % MOD;
    }
    cout << res << endl;
}
accuracy: 1
time_ms: 40
memory_kb: 20132
final_rank: 12

code_snippet: #include<bits/stdc++.h>
// #include<atcoder/all>
// #include<boost/multiprecision/cpp_int.hpp>

using namespace std;
// using namespace atcoder;
// using bint = boost::multiprecision::cpp_int;
using ll = long long;
using ull = unsigned long long;
using ld = long double;
using P = pair<ll,ll>;
using vi = vector<ll>;
using vvi = vector<vi>;
using vvvi = vector<vvi>;
using ve = vector<vector<int>>;
using vb = vector<bool>;
using vvb = vector<vb>;
#define rep(i,n) for(ll i = 0;i < (ll)n;i++)
#define ALL(x) (x).begin(),(x).end()
#define sz(c) ((ll)(c).size())
#define LB(A,x) (int)(lower_bound(A.begin(),A.end(),x)-A.begin())
#define UB(A,x) (int)(upper_bound(A.begin(),A.end(),x)-A.begin())
// #define MOD 1000000007
#define MOD 998244353
template<typename T>using min_priority_queue=priority_queue<T,vector<T>,greater<T>>;
template<typename T>ostream&operator<<(ostream&os,vector<T>&v){for(int i = 0;i < v.size();i++)os<<v[i]<<(i+1!=v.size()?" ":"");return os;}
template<typename T>istream&operator>>(istream&is,vector<T>&v){for(T&in:v)is>>in;return is;}
template<typename T1,typename T2>ostream&operator<<(ostream&os,pair<T1,T2>&p){os<<p.first<<" "<<p.second;return os;}
template<typename T1,typename T2>istream&operator>>(istream&is,pair<T1,T2>&p){is>>p.first>>p.second;return is;}
template<typename T> inline bool chmax(T &a,T b){if(a < b){a = b;return true;}return false;}
template<typename T> inline bool chmin(T &a,T b){if(a > b){a = b;return true;}return false;}
ld dist(ld x1,ld y1,ld x2, ld y2){return sqrtl((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));}

int connect(ve &v,int i,int idx,int &cnt,vi &id,bool is = false){
  v.emplace_back();
  if(is)id.emplace_back(cnt++);
  v[i].emplace_back(idx);v[idx].emplace_back(i);
  return idx+1;
}

// [l,r)
int rec(string &s,int l,int r,int &idx,ve &v,vi &prev,vi &id,int &cnt){
  v.emplace_back();idx++;
  int now_idx = idx-1;
  id.emplace_back(-1);
  l++;r--;
  if(s[l] == '1' && s[r-1] == '1'){
    idx = connect(v,now_idx,idx,cnt,id,1);
    idx = connect(v,now_idx,idx,cnt,id,1);
  }else if(s[l] == '1'){
    idx = connect(v,now_idx,idx,cnt,id,1);
    connect(v,now_idx,rec(s,l+1,r,idx,v,prev,id,cnt),cnt,id);
  }else if(s[r-1] == '1'){
    connect(v,now_idx,rec(s,l,r-1,idx,v,prev,id,cnt),cnt,id);
    idx = connect(v,now_idx,idx,cnt,id,1);
  }else{
    assert(prev[r-1] != -1);
    assert(prev[prev[r-1]-1] != -1);
    connect(v,now_idx,rec(s,prev[prev[r-1]-1],prev[r-1],idx,v,prev,id,cnt),cnt,id);
    connect(v,now_idx,rec(s,prev[r-1],r,idx,v,prev,id,cnt),cnt,id);
  }
  return now_idx;
};
P dfs(int ov,int pre,ve &v,vector<P> &ivl,vi &id){
  vector<P> k;
  for(auto nv : v[ov]){
    if(nv == pre)continue;
    k.emplace_back(dfs(nv,ov,v,ivl,id));
  }
  if(k.empty()){
    assert(ov < sz(id) && id[ov] != -1);
    return {id[ov],id[ov]};
  }
  assert(sz(k) == 2);
  ivl[k[0].second] = {k[0].first,k[1].second};
  return {k[0].first,k[1].second};
}

int main(){
  
  // ios_base::sync_with_stdio(0), cin.tie(0);
  string s,t;cin >> s >> t;
  if(s == "1"){
    cout << 1 << "\n";
    return 0;
  }
  auto stk = [](string &s)->vi{
    stack<int> st;
    vi prev(sz(s),-1);
    rep(i,sz(s)){
      if(s[i] == '(')st.push(i);
      else if(s[i] == ')'){
        prev[i] = st.top();st.pop();
      }
    }
    return prev;
  };
  vi preS(stk(s)),preT(stk(t));
  ve vS,vT;
  int idx = 0,cnt = 0;;
  vi idS,idT;
  rec(s,0,sz(s),idx,vS,preS,idS,cnt);
  idx = 0;cnt = 0;
  rec(t,0,sz(s),idx,vT,preT,idT,cnt);
  int n = cnt;
  vector<P> ivlS(n),ivlT(n);
  dfs(0,-1,vS,ivlS,idS);
  dfs(0,-1,vT,ivlT,idT);
  ll res = 1;
  rep(i,n-1){
    ll L = max(ivlS[i].first,ivlT[i].first);
    ll R = min(ivlS[i].second,ivlT[i].second);
    res = res*(R-i)%MOD*(i-L+1)%MOD;
  }
  cout << res << "\n";
  

  return 0;
}
accuracy: 1
time_ms: 130
memory_kb: 132488
final_rank: 16

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

//多倍長整数//
//#include <boost/multiprecision/cpp_int.hpp>
//namespace mp = boost::multiprecision;
//using bint = mp::cpp_int;

const int INF = 2e9;
const int MOD = 998244353;
const long long LINF = 5e18;

using ll = long long;
using vi = vector<int>;
using vl = vector<long long>;
using vs = vector<string>;
using vc = vector<char>;
using vb = vector<bool>;
using vvi = vector<vector<int>>;
using vvvi = vector<vector<vector<int>>>;
using vvvvi = vector<vector<vector<vector<int>>>>;
using vvl = vector<vector<long long>>;
using vvvl = vector<vector<vector<long long>>>;
using vvvvl = vector<vector<vector<vector<long long>>>>;
using vvc = vector<vector<char>>;
using vvb = vector<vector<bool>>;
using vvvb = vector<vector<vector<bool>>>;
using vvvvb = vector<vector<vector<vector<bool>>>>;

#define rep(i, n) for (int i = 0; i < (int)(n); i++)
#define dump(x)  cout << #x << " = " << (x) << endl;
#define Yes(n) cout << ((n) ? "Yes" : "No"  ) << endl
#define ALL(obj) (obj).begin(),(obj).end()

vector<pair<int,int>> f(string s){
	int n = s.size();
	int cnt = 0;
	rep(i,n) if(s[i] == '1') cnt++;
	vector<pair<int,int>> ret(cnt - 1);
	vi l,r;
	vi stk;
	cnt = 0;
	rep(i,n){
		if(s[i] == '('){
		}else if(s[i] == '1'){
			stk.push_back(l.size());
			l.push_back(cnt);
			r.push_back(++cnt);
		}else{
			int pos = r[stk[stk.size() - 2]] - 1;
			ret[pos] = {l[stk[stk.size() - 2]],r[stk[stk.size() - 1]]};
			stk.pop_back();
			stk.pop_back();
			stk.push_back(l.size());
			l.push_back(ret[pos].first);
			r.push_back(ret[pos].second);
		}
	}
	return ret;
}

int main(){
	string s,t;
	cin >> s >> t;
	vector<pair<int,int>> rets = f(s);
	vector<pair<int,int>> rett = f(t);
	ll ans = 1;
	rep(i,rets.size()){
		ans = (ans * (ll)(((ll)(i + 1 - max(rets[i].first,rett[i].first))*(min(rets[i].second,rett[i].second) - i - 1))%998244353))%998244353;
	}
	cout << ans << endl;
	return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 16800
final_rank: 5

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

//多倍長整数//
//#include <boost/multiprecision/cpp_int.hpp>
//namespace mp = boost::multiprecision;
//using bint = mp::cpp_int;

const int INF = 2e9;
const int MOD = 998244353;
const long long LINF = 5e18;

using ll = long long;
using vi = vector<int>;
using vl = vector<long long>;
using vs = vector<string>;
using vc = vector<char>;
using vb = vector<bool>;
using vvi = vector<vector<int>>;
using vvvi = vector<vector<vector<int>>>;
using vvvvi = vector<vector<vector<vector<int>>>>;
using vvl = vector<vector<long long>>;
using vvvl = vector<vector<vector<long long>>>;
using vvvvl = vector<vector<vector<vector<long long>>>>;
using vvc = vector<vector<char>>;
using vvb = vector<vector<bool>>;
using vvvb = vector<vector<vector<bool>>>;
using vvvvb = vector<vector<vector<vector<bool>>>>;

#define rep(i, n) for (int i = 0; i < (int)(n); i++)
#define dump(x)  cout << #x << " = " << (x) << endl;
#define Yes(n) cout << ((n) ? "Yes" : "No"  ) << endl
#define ALL(obj) (obj).begin(),(obj).end()

vector<pair<int,int>> f(string s){
	int n = s.size();
	int cnt = 0;
	rep(i,n) if(s[i] == '1') cnt++;
	vector<pair<int,int>> ret(cnt - 1);
	vi l,r;
	vi stk;
	cnt = 0;
	rep(i,n){
		if(s[i] == '('){
		}else if(s[i] == '1'){
			stk.push_back(l.size());
			l.push_back(cnt);
			r.push_back(++cnt);
		}else{
			int pos = r[stk[stk.size() - 2]] - 1;
			ret[pos] = {l[stk[stk.size() - 2]],r[stk[stk.size() - 1]]};
			stk.pop_back();
			stk.pop_back();
			stk.push_back(l.size());
			l.push_back(ret[pos].first);
			r.push_back(ret[pos].second);
		}
	}
	return ret;
}

int main(){
	string s,t;
	cin >> s >> t;
	vector<pair<int,int>> rets = f(s);
	vector<pair<int,int>> rett = f(t);
	ll ans = 1;
	rep(i,rets.size()){
		ans = (ans * ((ll)(i + 1 - max(rets[i].first,rett[i].first))*(min(rets[i].second,rett[i].second) - i - 1))%998244353)%998244353;
	}
	cout << ans << endl;
	return 0;
}
accuracy: 0.6444444444444445
time_ms: 20
memory_kb: 16796
final_rank: 17

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


#include <utility>

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`
    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);

}  // 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

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

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

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());
    }
    static_modint(bool 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());
    }
    dynamic_modint(bool 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

using namespace atcoder;

//多倍長整数//
//#include <boost/multiprecision/cpp_int.hpp>
//namespace mp = boost::multiprecision;
//using bint = mp::cpp_int;

const int INF = 2e9;
const int MOD = 998244353;
const long long LINF = 5e18;

using ll = long long;
using vi = vector<int>;
using vl = vector<long long>;
using vs = vector<string>;
using vc = vector<char>;
using vb = vector<bool>;
using vvi = vector<vector<int>>;
using vvvi = vector<vector<vector<int>>>;
using vvvvi = vector<vector<vector<vector<int>>>>;
using vvl = vector<vector<long long>>;
using vvvl = vector<vector<vector<long long>>>;
using vvvvl = vector<vector<vector<vector<long long>>>>;
using vvc = vector<vector<char>>;
using vvb = vector<vector<bool>>;
using vvvb = vector<vector<vector<bool>>>;
using vvvvb = vector<vector<vector<vector<bool>>>>;

#define rep(i, n) for (int i = 0; i < (int)(n); i++)
#define dump(x)  cout << #x << " = " << (x) << endl;
#define Yes(n) cout << ((n) ? "Yes" : "No"  ) << endl
#define ALL(obj) (obj).begin(),(obj).end()

vector<pair<int,int>> f(string s){
	int n = s.size();
	int cnt = 0;
	rep(i,n) if(s[i] == '1') cnt++;
	vector<pair<int,int>> ret(cnt - 1);
	vi l,r;
	vi stk;
	cnt = 0;
	rep(i,n){
		if(s[i] == '('){
		}else if(s[i] == '1'){
			stk.push_back(l.size());
			l.push_back(cnt);
			r.push_back(++cnt);
		}else{
			int pos = r[stk[stk.size() - 2]] - 1;
			ret[pos] = {l[stk[stk.size() - 2]],r[stk[stk.size() - 1]]};
			stk.pop_back();
			stk.pop_back();
			stk.push_back(l.size());
			l.push_back(ret[pos].first);
			r.push_back(ret[pos].second);
		}
	}
	return ret;
}

int main(){
	string s,t;
	cin >> s >> t;
	vector<pair<int,int>> rets = f(s);
	vector<pair<int,int>> rett = f(t);
	modint998244353 ans = 1;
	rep(i,rets.size()){
		ans *= (ll)(i + 1 - max(rets[i].first,rett[i].first))*(ll)(min(rets[i].second,rett[i].second) - i - 1);
	}
	cout << ans.val() << endl;
	return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 16800
final_rank: 5

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

//多倍長整数//
//#include <boost/multiprecision/cpp_int.hpp>
//namespace mp = boost::multiprecision;
//using bint = mp::cpp_int;

const int INF = 2e9;
const int MOD = 998244353;
const long long LINF = 5e18;

using ll = long long;
using vi = vector<int>;
using vl = vector<long long>;
using vs = vector<string>;
using vc = vector<char>;
using vb = vector<bool>;
using vvi = vector<vector<int>>;
using vvvi = vector<vector<vector<int>>>;
using vvvvi = vector<vector<vector<vector<int>>>>;
using vvl = vector<vector<long long>>;
using vvvl = vector<vector<vector<long long>>>;
using vvvvl = vector<vector<vector<vector<long long>>>>;
using vvc = vector<vector<char>>;
using vvb = vector<vector<bool>>;
using vvvb = vector<vector<vector<bool>>>;
using vvvvb = vector<vector<vector<vector<bool>>>>;

#define rep(i, n) for (int i = 0; i < (int)(n); i++)
#define dump(x)  cout << #x << " = " << (x) << endl;
#define Yes(n) cout << ((n) ? "Yes" : "No"  ) << endl
#define ALL(obj) (obj).begin(),(obj).end()

vector<pair<int,int>> f(string s){
	int n = s.size();
	int cnt = 0;
	rep(i,n) if(s[i] == '1') cnt++;
	vector<pair<int,int>> ret(cnt - 1);
	vi l,r;
	vi stk;
	cnt = 0;
	rep(i,n){
		if(s[i] == '('){
		}else if(s[i] == '1'){
			stk.push_back(l.size());
			l.push_back(cnt);
			r.push_back(++cnt);
		}else{
			int pos = r[stk[stk.size() - 2]] - 1;
			ret[pos] = {l[stk[stk.size() - 2]],r[stk[stk.size() - 1]]};
			stk.pop_back();
			stk.pop_back();
			stk.push_back(l.size());
			l.push_back(ret[pos].first);
			r.push_back(ret[pos].second);
		}
	}
	return ret;
}

int main(){
	string s,t;
	cin >> s >> t;
	vector<pair<int,int>> rets = f(s);
	vector<pair<int,int>> rett = f(t);
	ll ans = 1;
	rep(i,rets.size()){
		ans = (ans * (ll)(i + 1 - max(rets[i].first,rett[i].first))*(min(rets[i].second,rett[i].second) - i - 1))%998244353;
	}
	cout << ans << endl;
	return 0;
}
accuracy: 0.6444444444444445
time_ms: 20
memory_kb: 16868
final_rank: 18

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pi;
#define FOR(i,l,r) for(ll i=(l);i<(r);i++)
#define REP(i,n) FOR(i,0,n)
vector<pi>con(string S){
  ll N=S.size();
  stack<ll>st;
  vector<ll>last(N);
  REP(i,N){
    if(S[i]=='(')st.emplace(i);
    if(S[i]==')'){
      last[i]=st.top();
      st.pop();
    }
  }
  ll M=N/3+1;
  vector<pi>ans(M);
  vector<ll>cnt(N);
  REP(i,N){
    if(i)cnt[i]=cnt[i-1];
    if(i&&S[i-1]=='1')cnt[i]++;
  }
  function<pi(ll,ll)>dfs=[&](ll l,ll r){
    if(S[l]=='1')return pi(cnt[l],cnt[l]);
    ll m=last[r-2];
    if(S[r-2]=='1')m=r-2;
    auto L=dfs(l+1,m);
    auto R=dfs(m,r-1);
    assert(L.second+1==R.first);
    ans[L.second]=pi(L.first,R.second);
    return pi(L.first,R.second);
  };
  dfs(0,N);
  return ans;
}
int main(){
  string S,T;cin>>S>>T;
  if(S.size()==1){
    cout<<1<<endl;return 0;
  }
  auto X=con(S),Y=con(T);
  ll ans=1;
  ll mod=998244353;
  REP(i,X.size()-1){
    ll l=max(X[i].first,Y[i].first);
    ll r=min(X[i].second,Y[i].second);
    ans=ans*(i-l+1)%mod*(r-i)%mod;
  }
  cout<<ans<<endl;
  return 0;
}
accuracy: 1
time_ms: 30
memory_kb: 43468
final_rank: 15

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int INF = (int)1e9 + 1001010;
const ll llINF = (long long)4e18 + 22000020;
const string endn = "\n";
template <class T> inline auto vector2(size_t i, size_t j, const T &init = T()) {
    return vector(i, vector<T>(j, init));
}
const string ELM_SEP = " ", VEC_SEP = endn;
template <class T> istream &operator>>(istream &i, vector<T> &A) {
    for(auto &I : A) i >> I;
    return i;
}
template <class T> ostream &operator<<(ostream &o, const vector<T> &A) {
    int i = A.size();
    for(const auto &I : A) o << I << (--i ? ELM_SEP : "");
    return o;
}
template <class T> ostream &operator<<(ostream &o, const vector<vector<T>> &A) {
    int i = A.size();
    for(const auto &I : A) o << I << (--i ? VEC_SEP : "");
    return o;
}
template <class T> vector<T> &operator++(vector<T> &A, int) {
    for(auto &I : A) I++;
    return A;
}
template <class T> vector<T> &operator--(vector<T> &A, int) {
    for(auto &I : A) I--;
    return A;
}
template <class T, class U> bool chmax(T &a, const U &b) { return ((a < b) ? (a = b, true) : false); }
template <class T, class U> bool chmin(T &a, const U &b) { return ((a > b) ? (a = b, true) : false); }
ll floor(ll a, ll b) {
    if(b < 0) a = -a, b = -b;
    return (a >= 0) ? a / b : (a + 1) / b - 1;
}
ll ceil(ll a, ll b) {
    if(b < 0) a = -a, b = -b;
    return (a > 0) ? (a - 1) / b + 1 : a / b;
}
ll check_bit(unsigned long long val, unsigned long long digit) { return (val >> digit) & 1; }
#ifdef DEBUG
#include <cpp-dump/cpp-dump.hpp>
#define dump(...) cpp_dump(__VA_ARGS__)
namespace cp = cpp_dump;
struct InitCppDump {
    InitCppDump() {
        if(!isatty(fileno(stderr))) CPP_DUMP_SET_OPTION(es_style, cpp_dump::types::es_style_t::no_es);
        CPP_DUMP_SET_OPTION(log_label_func, cp::log_label::line());
        CPP_DUMP_SET_OPTION(max_iteration_count, 30);
    }
} init_cpp_dump;
#else
#define dump(...)
#endif
// ==================== ここまでテンプレ ====================

// modint
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;
    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;
        unsigned long long x =
            (unsigned long long)(((unsigned __int128)(z)*im) >> 64);
        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;
    for (long long a : {2, 7, 61}) {
        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};
}


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_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;
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>;
}  // namespace internal
template <int m, std::enable_if_t<(1 <= m)>* = nullptr>
struct static_modint {
    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());
    }
    static_modint(bool 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; }

    friend istream &operator >> (istream &i, mint &a) {long long v; i >> v; a = v; return i;}
    friend ostream &operator << (ostream &os, const mint &a) { return os << a.val(); }
  private:
    unsigned int _v;
    static constexpr unsigned int umod() { return m; }
    static constexpr bool prime = internal::is_prime<m>;
};

using modint998244353 = static_modint<998244353>;
using modint1000000007 = static_modint<1000000007>;
}  // namespace atcoder
using namespace atcoder;
using mint = modint998244353;
// using mint = modint1000000007;

int main(int argc, char *argv[]){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    string s, t; cin >> s >> t;

    auto parse_string = [&](string s) -> pair<vector<ll>, vector<ll>> {
        int v_iter = 0;
        int idx = 0;
        vector<ll> left, right;
        auto dfs = [&](auto &&dfs) -> pair<ll, ll> {
            char c = s[idx++];
            if(c == '1'){
                pair<ll, ll> ret = {v_iter, v_iter};
                v_iter++;
                return ret;
            }
            else if(c == '('){
                auto [l1, r1] = dfs(dfs);
                auto [l2, r2] = dfs(dfs);
                assert(r1 + 1 == l2);
                assert(s[idx] == ')');
                idx++;

                // update left, right
                if(left.size() <= r1) left.resize(r1 + 1);
                if(right.size() <= r1) right.resize(r1 + 1);

                left[r1] = r1 - l1 + 1;
                right[r1] = r2 - l2 + 1;
                return {l1, r2};
            }
            else{
                cerr << "Invalid" << endl;
                exit(1);
            }
        };
        dfs(dfs);

        return {left, right};
    };

    auto [left_s, right_s] = parse_string(s);
    auto [left_t, right_t] = parse_string(t);

    mint ans = 1;
    for(int i = 0; i < left_s.size(); i++){
        ans *= min(left_s[i], left_t[i]) * min(right_s[i], right_t[i]);
    }
    cout << ans << endl;
    return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 37536
final_rank: 11

code_snippet: #ifdef DEBUG
#include"stdlibrary.h"
#else
// #pragma GCC target("avx")
// #pragma GCC optimize("O3")
// #pragma GCC optimize("unroll-loops")
#include<bits/stdc++.h>
using namespace std;
#endif
// #include<ext/pb_ds/assoc_container.hpp>
// #include<ext/pb_ds/tree_policy.hpp>
// #include<ext/pb_ds/tag_and_trait.hpp>
// using namespace __gnu_pbds;
// #include<boost/multiprecision/cpp_int.hpp>
// namespace multiprecisioninteger = boost::multiprecision;
// using cint=multiprecisioninteger::cpp_int;
using ll=long long;
using datas=std::pair<ll,ll>;
using ddatas=std::pair<long double,long double>;
using tdata=std::pair<ll,datas>;
using vec=std::vector<ll>;
using mat=std::vector<vec>;
using pvec=std::vector<datas>;
using pmat=std::vector<pvec>;
// using llset=tree<ll,null_type,less<ll>,rb_tree_tag,tree_order_statistics_node_update>;
#define For(i,a,b) if(const std::int64_t _iterate_from=a,_iterate_to=b;_iterate_from<_iterate_to)for(const std::int64_t i:std::views::iota(_iterate_from,_iterate_to))
#define bFor(i,b,a) for(ll i=b-1;i>=(ll)a;--i)
#define rep(i,N) For(i,0,N)
#define rep1(i,N) For(i,1,N)
#define brep(i,N) bFor(i,N,0)
#define brep1(i,N) bFor(i,N,1)
#define all(v) std::begin(v),std::end(v)
#define allr(v) std::rbegin(v),std::rend(v)
#define vsort(v) std::sort(all(v))
#define vrsort(v) std::sort(allr(v))
#define uniq(v) vsort(v),(v).erase(std::unique(all(v)),std::end(v))
#define endl "\n"
#define popcount __builtin_popcountll
#define print(x) std::cout<<x<<endl
#define printyes print("Yes")
#define printno print("No")
#define printYES print("YES")
#define printNO print("NO")
#define output(v) do{bool f=0;for(auto outi:v){std::cout<<(f?" ":"")<<outi;f=1;}std::cout<<endl;}while(0)
#define matoutput(v) do{for(auto outimat:v)output(outimat);}while(0)
// constexpr ll mod=1000000007;
constexpr ll mod=998244353;
constexpr ll inf=1LL<<60;
constexpr long double eps=1e-9;
const long double PI=acosl(-1);
template<class T,auto x=T::mod()> std::ostream& operator<<(std::ostream& os,const T& v){return os<<v.val();}
template<class T> std::ostream& operator<<(std::ostream& os,const std::vector<T>& v);
template<class T,class F> std::ostream& operator<<(std::ostream& os,const std::set<T,F>& v);
template<class T,class F> std::ostream& operator<<(std::ostream& os,const std::multiset<T,F>& v);
template<class T,class E,class F> std::ostream& operator<<(std::ostream& os,const std::map<T,E,F>& v);
template<class T,class E> std::ostream& operator<<(std::ostream& os,const std::pair<T,E>& p){return os<<"("<<p.first<<","<<p.second<<")";}
template<class T> std::ostream& operator<<(std::ostream& os,const std::vector<T>& v){
  os<<"{";bool f=false;
  for(auto& x:v){if(f)os<<",";os<<x;f=true;}
  os<<"}";
  return os;
}
template<class T,class F> std::ostream& operator<<(std::ostream& os,const std::set<T,F>& v){
  os<<"{";bool f=false;
  for(auto& x:v){if(f)os<<",";os<<x;f=true;}
  os<<"}";
  return os;
}
template<class T,class F> std::ostream& operator<<(std::ostream& os,const std::multiset<T,F>& v){
  os<<"{";bool f=false;
  for(auto& x:v){if(f)os<<",";os<<x;f=true;}
  os<<"}";
  return os;
}
template<class T,class E,class F> std::ostream& operator<<(std::ostream& os,const std::map<T,E,F>& v){
  os<<"{";bool f=false;
  for(auto& x:v){if(f)os<<",";os<<x;f=true;}
  os<<"}";
  return os;
}
template<class T> inline bool chmax(T& a,const T b){bool x=a<b;if(x)a=b;return x;}
template<class T> inline bool chmin(T& a,const T b){bool x=a>b;if(x)a=b;return x;}
#ifdef DEBUG
void debugg(){std::cout<<endl;}
template<class T,class... Args>void debugg(const T& x,const Args&... args){std::cout<<" "<<x;debugg(args...);}
#define debug(...) cout<<__LINE__<<" ["<<#__VA_ARGS__<<"]:",debugg(__VA_ARGS__)
#else
#define debug(...) (void(0))
#endif

inline void startupcpp(void) noexcept{
  cin.tie(0)->sync_with_stdio(0);
  cout<<fixed<<setprecision(15);
}

ll modinv(ll a,const ll m=mod) noexcept{
  ll b=m,u=1,v=0,t;
  while(b){
    t=a/b;
    a-=t*b; swap(a,b);
    u-=t*v; swap(u,v);
  }
  return (u+m)%m;
}

ll moddevide(const ll a,const ll b) noexcept{return (a*modinv(b))%mod;}

vec modncrlistp,modncrlistm;

ll modncr(const ll n,const ll r){
  if(n<r||r<0)return 0;
  ll i,size=modncrlistp.size();
  if(size<=n){
    modncrlistp.resize(n+1);
    modncrlistm.resize(n+1);
    if(!size){
      modncrlistp[0]=modncrlistm[0]=1;
      size++;
    }
    For(i,size,n+1)modncrlistp[i]=modncrlistp[i-1]*i%mod;
    modncrlistm[n]=modinv(modncrlistp[n]);
    for(i=n;i>size;--i)modncrlistm[i-1]=modncrlistm[i]*i%mod;
  }
  return modncrlistp[n]*modncrlistm[r]%mod*modncrlistm[n-r]%mod;
}

ll modpow(ll a,ll n,const ll m=mod){
  if(n<0)return 0;
  ll res=1;
  while(n>0){
    if(n&1)res=res*a%m;
    a=a*a%m;
    n>>=1;
  }
  return res;
}

constexpr ll gcd(const ll a,const ll b) noexcept{return (!b)?abs(a):(a%b==0)?abs(b):gcd(b,a%b);}
constexpr ll lcm(const ll a,const ll b) noexcept{return a/gcd(a,b)*b;}

#include<atcoder/all>
using mint=atcoder::modint998244353;
// void operator>>(istream& is,mint& v){long long x;is>>x;v=x;}

pvec parse(const std::string& s){
  vec ones(s.size()+1);
  rep(i,s.size())ones[i+1]=ones[i]+(s[i]=='1');
  vec p(s.size());
  {
    vec st;
    rep(i,s.size()){
      if(s[i]=='1'){
        p[i]=-1;
        continue;
      }
      if(s[i]=='('){
        st.push_back(i);
        continue;
      }
      assert(s[i]==')'&&st.size());
      p[i]=st.back();
      p[st.back()]=i;
      st.pop_back();
    }
  }

  pvec res(ones.back());
  rep1(i,s.size())if(s[i-1]=='1'&&s[i]=='1')res[ones[i]].first=res[ones[i]].second=1;
  rep1(i,s.size())if(s[i-1]=='1'&&s[i]=='('){
    res[ones[i]].first=1;
    res[ones[i]].second=ones[p[i]]-ones[i];
  }
  rep1(i,s.size())if(s[i-1]==')'&&s[i]=='1'){
    res[ones[i]].first=ones[i-1]-ones[p[i-1]];
    res[ones[i]].second=1;
  }
  rep1(i,s.size())if(s[i-1]==')'&&s[i]=='('){
    res[ones[i]].first=ones[i-1]-ones[p[i-1]];
    res[ones[i]].second=ones[p[i]]-ones[i];
  }
  res.erase(res.begin());
  return res;
}

int main(){
  startupcpp();
  string s,t;
  cin>>s>>t;
  auto v1=parse(s),v2=parse(t);
  debug(v1,v2);
  assert(v1.size()==v2.size());
  mint res=1;
  rep(i,v1.size()){
    res*=min(v1[i].first,v2[i].first)*min(v1[i].second,v2[i].second);
  }
  print(res);
}
accuracy: 1
time_ms: 20
memory_kb: 23256
final_rank: 8