Problem:
F: Ribbons on A Perfect Binary Tree
問題
長さ $2 i$ ($1 \leq i \leq n$) のリボンがそれぞれ $a_i$ 個ある。
リボンはそれぞれ互いに区別できる。
また、高さが $n$ で葉の個数が $2^n$ の完全二分木がある。
あなたは、以下のような手順で、完全二分木にすべてのリボンを飾り付けていく。
はじめ、全ての頂点は
装飾済み
ではない。
異なる 2 つの葉 $u$, $v$ を選ぶ。このとき、$u$-$v$ パスに含まれる辺の数が、リボンの長さと等しくなければならない。また、$u$-$v$ パスに含まれる頂点はいずれも
装飾済み
であってはならない。
$u$ から $v$ へのパス上の頂点全てを
装飾済み
にする。
以下にリボンの飾り付け方の具体例を示す。
条件を満たすリボンの飾り付け方が何通りあるかを求め、 $998244353$ で割った余りを出力せよ。
条件を満たすリボンの飾り付け方が存在しない場合、$0$ を出力せよ。
なお、リボンが一つも存在しないときは $1$ 通りであることに注意せよ。
ただし、2 つのリボンの飾り付け方が異なるとは、
あるリボンが存在し、そのリボンをかけるために選んだ 2 つの葉 $u$, $v$ が異なることを言う。
入力形式
$n$
$a_1$ ... $a_n$
制約
$1 \leq n \leq 2000$
$0 \leq a_i \leq 2000$ ($1 \leq i \leq n$)
出力形式
リボンの飾り付け方の通り数を求め、$998244353$ で割った余りを一行に出力せよ。
入力例 1
2
1 0
出力例 1
2
条件を満たすリボンの飾り付け方は図の 2 通りである。
入力例 2
2
0 1
出力例 2
4
条件を満たすリボンの飾り付け方は図の 4 通りである。
入力例 3
2
2 0
出力例 3
2
条件を満たすリボンの飾り付け方は図の 2 通りである。
入力例 4
2
1 1
出力例 4
0
条件を満たすリボンの飾り付け方は存在しない。

Submitted solutions:

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

template <ll mod>
struct BinomMod {
    int N;
    vector<ll> F, invF;

    inline ll norm(ll x) {
        return ((x % mod) + mod) % mod;
    }

    inline ll mul(ll a, ll b) {
        return norm(a * b);
    }

    inline bool rangeCheck(int n) {
        return 0 <= n and n < N;
    }

    ll modinv(ll a) {
        ll res = 1, base = a;
        ll p = mod - 2;
        while (p) {
            if (p & 1) res = mul(res, base);
            base = mul(base, base);
            p >>= 1;
        }
        return res;
    }

    BinomMod(int sz) : N(sz + 1), F(sz + 1, 1), invF(sz + 1) {
        for (int i = 0 ; i < N ; i++) {
            F[i + 1] = mul(F[i], i + 1);
        }

        invF[N] = modinv(F[N]);

        for (int i = N ; i > 0 ; i--) {
            invF[i - 1] = mul(i, invF[i]);
        }
    }


    ll Fac(int n) {
        assert(rangeCheck(abs(n)));
        return (n >= 0 ? F[n] : invF[-n]);
    }

    ll P(int n, int r) {
        assert(rangeCheck(n) and rangeCheck(r));
        if (n < r) return 0;
        return mul(Fac(n), Fac(-(n - r)));
    }

    ll C(int n, int r) {
        assert(rangeCheck(n) and rangeCheck(r));
        if (n < r) return 0;
        return mul(P(n, r), Fac(-r));
    }

    ll H(int n, int r) {
        if (n == 0 and r == 0) return 1;
        return C(n + r - 1, r);
    }
};

const ll mod = 998244353;

ll norm(ll x) {
    return ((x % mod) + mod) % mod;
}

ll add(ll a, ll b) {
    return norm(a + b);
}

ll inv(ll a) {
    return (a == 0 ? 0 : mod - a);
}

ll sub(ll a, ll b) {
    return add(a, inv(b));
}

ll mul(ll a, ll b) {
    return norm(a * b);
}

ll modpow(ll a, ll p) {
    ll res = 1, base = a;
    while (p) {
        if (p & 1) res = mul(res, base);
        base = mul(base, base);
        p >>= 1;
    }
    return res;
}

int main() {
    ll N; cin >> N;
    vector<ll> A(N);
    for (auto& a : A) cin >> a;

    vector<ll> P2(N + 100, 1LL);
    for (int i = 0 ; i + 1 < (int)P2.size() ; i++) {
        P2[i + 1] = mul(P2[i], 2);
    }

    vector<ll> X(N);
    for(int i = 0; i < N; i++){
        ll val = P2[i];
        for(int j = 0; j < i ; j++){
            val = sub(val, mul(2, A[N - j - 1]));
        }    
        X[i] = val;
    } 
    

    ll ans = 1LL;
    for (int i = 0 ; i < N ; i++) {
        ll fC = 1LL;
        for (int j = 0 ; j < A[N - i - 1] ; j++) {
            fC = mul(fC, X[i] - j);
        }
        ll bC = P2[N - i - 1];
        bC = mul(bC, bC);
        bC = modpow(bC, A[N - i - 1]);

        ans = mul(ans, mul(fC, bC));
    }

    cout << ans << endl;
}
accuracy: 1
time_ms: 10
memory_kb: 3480
final_rank: 4

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

using namespace std;


using ll = long long;
const ll MOD = 998244353;

ll f(ll n){
  n %= MOD;
  n += MOD;
  n %= MOD;
  return n;
}

ll modadd(ll x,ll y){
  return f(x + y);
}

ll modmul(ll x,ll y){
  return f(x * y);
}

ll modpow(ll x,ll y){
  ll res = 1;
  while(y){
    if(y&1){
      res = modmul(res, x);
    }
    x = modmul(x, x);
    y = y >> 1;
  }
  return res;
}

ll modinv(ll n){
  return modpow(n, MOD-2);
}

ll moddiv(ll x,ll y){
  return modmul(x,modinv(y));
}

ll factorial(ll n){
  static vector<ll> dp(2,1);
  while(dp.size() <= n){
    ll add = modmul(dp.back(), dp.size());
    dp.emplace_back(add);
  }
  return dp[n];
}

ll permutation(ll a, ll b){
  if(a < b){
    return 0;
  }
  ll res = 1;
  for(int i=0;i<b;++i){
    res = modmul(res, a-i);
  }
  return res;
}

ll func(){
  int n;
  cin >> n;
  vector<ll> pow2(1e4);
  pow2[0] = 1;
  for(int i=1;i<pow2.size();++i){
    pow2[i] = modmul(pow2[i-1], 2);
  }

  vector<ll> ribons(n);
  for(auto &i:ribons)cin >> i;
  vector<ll> cans(n,0);
  vector<bool> over_flow(n,false);
  cans.back() = 1;
  ll res = 1;
  for(int i=n-1;i>=0;--i){
    if(not over_flow[i]){
      if(cans[i] < ribons[i])return 0;
    }
    for(int j=i-2;j>=0;--j){
      cans[j] = modadd(cans[j], modmul(2,ribons[i]));
      if(cans[j] > 1e4 or over_flow[i]){
        over_flow[j] = true;
      }
    }
    if(i >= 1){
      cans[i-1] = modadd(cans[i-1], modmul(2, cans[i] - ribons[i]));
      if(cans[i-1] > 1e4 or over_flow[i]){
        over_flow[i] = true;
      }
    }
    res = modmul(res, permutation(cans[i], ribons[i]));
    res = modmul(res, modpow(pow2[i], ribons[i] * 2));
  }
  return res;
}

int main(){
  cout << func() << endl;
}
accuracy: 1
time_ms: 10
memory_kb: 3556
final_rank: 5

code_snippet: #include <bits/stdc++.h>
#pragma GCC optimize("Ofast")
using namespace std;
using std::cout;
using std::cin;
using std::endl;
using ll=long long;
using ld=long double;
ll ILL=9167167167167167167;
const int INF=100000000;
const ll mod=998244353;
#define rep(i,a) for (int i=0;i<a;i++)
#define all(p) p.begin(),p.end()
template<class T> using _pq = priority_queue<T, vector<T>, greater<T>>;
template<class T> ll LB(vector<T> &v,T a){return lower_bound(v.begin(),v.end(),a)-v.begin();}
template<class T> ll UB(vector<T> &v,T a){return upper_bound(v.begin(),v.end(),a)-v.begin();}
template<class T> bool chmin(T &a,const T &b){if(a>b){a=b;return 1;}else return 0;}
template<class T> bool chmax(T &a,const T &b){if(a<b){a=b;return 1;}else return 0;}
template<class T> void So(vector<T> &v) {sort(v.begin(),v.end());}
template<class T> void Sore(vector<T> &v) {sort(v.begin(),v.end(),[](T x,T y){return x>y;});}
void yneos(bool a){if(a) cout<<"Yes\n"; else cout<<"No\n";}
template<class T> void vec_out(vector<T> &p){for(int i=0;i<(int)(p.size());i++){if(i) cout<<" ";cout<<p[i];}cout<<"\n";}


ll jyo(ll x,ll y,ll z){
  ll H=y; //ここから
       ll a=1,b=(x%z+z)%z,c=1;
       while(H>0){
         a*=2;
         if(H%a!=0){
           H-=a/2;
           c*=b;
           c%=z;
         }
        b*=b;
         b%=z;
      } //ここまで
 return c;
}

ll Comb(ll a,ll b){
	ll X=1,Y=1;
	rep(i,b){
		X=(X*(a-i))%mod;
		Y=(Y*(i+1))%mod;
	}
	return (X*jyo(Y,mod-2,mod))%mod;
}

void solve();
// oddloop
int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	
	int t=1;
	//cin>>t;
	rep(i,t) solve();
}

void solve(){
	int n;
	cin>>n;
	vector<ll> A(n);
	rep(i,n) cin>>A[i];
	ll ans=1,B=1,C=0;
	for(int i=n-1;i>=0;i--){
		ans=(ans*jyo(2,2*i*A[i],mod))%mod;
		ans=(ans*Comb(B,A[i]))%mod;
		for(ll j=1;j<=A[i];j++) ans=(ans*j)%mod;
		B-=A[i];
		B*=2ll;
		B%=mod;
		B+=C*2;
		C+=A[i];
	}
	cout<<ans<<"\n";
}
accuracy: 1
time_ms: 10
memory_kb: 3452
final_rank: 3

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 9223372036854775807
//#define MOD 1000000007
#define EPS 0.000000001
using namespace std;

#define MOD 998244353
#define SIZE 2005
#define MAX 23


int N;
ll POW[SIZE],A[SIZE];
ll rest[SIZE];

int main(){

	POW[0] = 1;
	for(int i = 1; i < SIZE; i++){

		POW[i] = POW[i-1]*4;
		POW[i] %= MOD;
	}

	rest[1] = 1;
	for(int i = 2; i < SIZE; i++){

		rest[i] = rest[i-1]*2;
		rest[i] %= MOD;
	}

	scanf("%d",&N);

	ll sum = 0;

	for(int i = 1; i <= N; i++){

		scanf("%lld",&A[i]);
		sum += A[i];
	}
	if(sum == 0){

		printf("1\n");
		return 0;
	}

	ll ans = 1;

	for(int i = N; i >= 1; i--){
		if(A[i] == 0)continue;

		if(A[i] > rest[(N+1)-i]){
			printf("0\n");
			return 0;
		}
		for(int k = (N+1)-i+1; k <= MAX; k++){

			if(rest[k] < A[i]*2){
				printf("0\n");
				return 0;
			}
		}

		ll tmp = rest[(N+1)-i];
		//printf("\ni:%d tmp:%lld\n",i,tmp);

		for(ll k = 1; k < A[i]; k++){

			tmp *= ((rest[(N+1)-i]-k)+MOD)%MOD;
			tmp %= MOD;
		}

		for(ll k = 0; k < A[i]; k++){
			tmp *= POW[i-1];
			tmp %= MOD;
		}

		ans *= tmp;
		ans %= MOD;

		rest[(N+1)-i] -= A[i];
		if((N+1)-i > MAX && rest[(N+1)-i] < 0){

			rest[(N+1)-i] += MOD;
		}

		for(int k = (N+1)-i+1; k <= N; k++){

			rest[k] -= A[i]*2;
			if(k > MAX && rest[k] < 0){

				rest[k] += MOD;
			}
		}
	}

	printf("%lld\n",ans);

	return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 3264
final_rank: 1

code_snippet: #include <bits/stdc++.h>
//#include <atcoder/all>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> l_l;
typedef pair<int, int> i_i;
template<class T>
inline bool chmax(T &a, T b) {
    if(a < b) {
        a = b;
        return true;
    }
    return false;
}

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

const long long INF = 1e18;
const ll mod = 998244353;
ll N;
ll a[2010];
ll ans = 1;
vector<ll> inv, FactorialInv, Factorial;
ll beki(ll a, ll b){
    ll ret = 1 % mod;
    a %= mod;
    while(b) {
        if(b & 1LL) ret = ret * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return ret;
}
void init_combination(ll MAX){
    Factorial.resize(MAX + 1);
    FactorialInv.resize(MAX + 1);
    inv.resize(MAX + 1);
    Factorial[0] = 1;
    inv[0] = 1;
    for(int i = 1; i <= MAX; i++){
        Factorial[i] = Factorial[i - 1] * i % mod;
    }
    FactorialInv[MAX] = beki(Factorial[MAX], mod - 2);
    for(ll i = MAX - 1; i >= 0; i--) {
        FactorialInv[i] = FactorialInv[i+1] * (i+1) % mod;
    }
    for(int i = 1; i <= MAX; i++) {
        inv[i] = FactorialInv[i] * Factorial[i-1] % mod;
    }
}
ll combination(ll a, ll b){
    if((a == b) || (b == 0)){
        return 1;
    }
    if(a < b) return 0;
    if(b < 0) return 0;
    ll ans = Factorial[a] * FactorialInv[b] % mod;
    ans = ans * FactorialInv[a - b] % mod;
    return ans;
}

ll combination2(ll a, ll b){
    if((a == b) || (b == 0)){
        return 1;
    }
    if(a < b) return 0;
    if(b < 0) return 0;
    ll ret = 1;
    for(ll i = 0; i < b; i++) {
        ret *= (a - i) % mod;
        ret %= mod;
        ret *= inv[i + 1];
        ret %= mod;
    }
    return ret;
}

ll num[2005];

int main() {
    cin >> N;
    init_combination(1000000);
    for(int i = 0; i < N; i++) cin >> a[i];
    num[N-1] = 1;
    for(int i = N - 1; i >= 0; i--) {
        ll factor = combination2(num[i], a[i]);
        factor *= Factorial[a[i]];
        factor %= mod;
        ll c = beki(2, i);
        factor *= beki(c * c % mod, a[i]);
        factor %= mod;
        //cerr << i << " " << num << " " << a[i] << " " << factor << endl;
        ans *= factor;
        ans %= mod;
        for(int j = i - 2; j >= 0; j--) {
            num[j] += 2 * a[i];
            num[j] %= mod;
        }
        num[i] += mod - a[i];
        num[i-1] += 2 * num[i];
        num[i-1] %= mod;
    }
    cout << ans << endl;
    return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 26584
final_rank: 7

code_snippet: #include <iostream>
#include <string>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <unordered_map>
#include <map>
#include <set>
#include <algorithm>
#include <queue>
#include <stack>
#include <functional>
#include <bitset>
#include <assert.h>
#include <unordered_map>
#include <fstream>
#include <ctime>
#include <complex>
//#include <atcoder/all>
using namespace std;
//using namespace atcoder;
typedef long long ll;
typedef vector<ll> vl;
typedef vector<vl> vvl;
typedef vector<char> vc;
typedef vector<string> vs;
typedef vector<bool> vb;
typedef vector<double> vd;
typedef pair<ll,ll> P;
typedef pair<int,int> pii;
typedef vector<P> vpl;
typedef tuple<ll,ll,ll> tapu;
#define rep(i,n) for(int i=0; i<(n); i++)
#define REP(i,a,b) for(int i=(a); i<(b); i++)
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
const int inf = 1<<30;
const ll linf = 1LL<<62;
const int MAX = 510000;
ll dy[8] = {1,-1,0,0,1,-1,1,-1};
ll dx[8] = {0,0,1,-1,1,-1,-1,1};
const double pi = acos(-1);
const double eps = 1e-7;
template<typename T1,typename T2> inline bool chmin(T1 &a,T2 b){
	if(a>b){
		a = b; return true;
	}
	else return false;
}
template<typename T1,typename T2> inline bool chmax(T1 &a,T2 b){
	if(a<b){
		a = b; return true;
	}
	else return false;
}
template<typename T> inline void print(T &a){
    for(auto itr = a.begin(); itr != a.end(); itr++){
		cout << *itr << " ";
	}
    cout << "\n";
}
template<typename T1,typename T2> inline void print2(T1 a, T2 b){
	cout << "debug: " << a << " " << b << "\n";
}
template<typename T1,typename T2,typename T3> inline void print3(T1 a, T2 b, T3 c){
	cout << "debug: " << a << " " << b << " " << c << "\n";
}
void mark() {cout << "#" << "\n";}
ll pcount(ll x) {return __builtin_popcountll(x);}
//const int mod = 1e9 + 7;
const int mod = 998244353;

template <std::uint_fast64_t Modulus> class modint {
  using u64 = std::uint_fast64_t;

public:
  u64 a;

  constexpr modint(const u64 x = 0) noexcept : a(x % Modulus) {}
  constexpr u64 &value() noexcept { return a; }
  constexpr const u64 &value() const noexcept { return a; }
  constexpr modint operator+(const modint rhs) const noexcept {
    return modint(*this) += rhs;
  }
  constexpr modint operator-(const modint rhs) const noexcept {
    return modint(*this) -= rhs;
  }
  constexpr modint operator*(const modint rhs) const noexcept {
    return modint(*this) *= rhs;
  }
  constexpr modint operator/(const modint rhs) const noexcept {
    return modint(*this) /= rhs;
  }
  constexpr modint &operator+=(const modint rhs) noexcept {
    a += rhs.a;
    if (a >= Modulus) {
      a -= Modulus;
    }
    return *this;
  }
  constexpr modint &operator-=(const modint rhs) noexcept {
    if (a < rhs.a) {
      a += Modulus;
    }
    a -= rhs.a;
    return *this;
  }
  constexpr modint &operator*=(const modint rhs) noexcept {
    a = a * rhs.a % Modulus;
    return *this;
  }
  constexpr modint &operator/=(modint rhs) noexcept {
    u64 exp = Modulus - 2;
    while (exp) {
      if (exp % 2) {
        *this *= rhs;
      }
      rhs *= rhs;
      exp /= 2;
    }
    return *this;
  }
};

using mint = modint<mod>;

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

vector<ll> fac(MAX), finv(MAX), inv(MAX);

void comInit(){
    fac[0] = fac[1] = 1;
    finv[0] = finv[1] = 1;
    inv[1] = 1;
    for(ll i=2; i<MAX; i++){
        fac[i] = fac[i-1]*i % mod;
        inv[i] = mod - inv[mod%i] * (mod/i) % mod;
        finv[i] = finv[i-1] * inv[i] % mod;
    }
}


ll com(ll n, ll k){
    if(n < k) return 0;
    if(n < 0 || k < 0) return 0;
    return fac[n] * (finv[k] * finv[n-k] % mod) % mod;
}

mint comb(ll n, ll k){
    if(n < 0) return 0;
    if(n < k) return 0;
    mint res = 1;
    rep(i,k){
        res *= n-i;
    }
    return res;
}

int main(){
    int n; cin >> n;
    vl a(n); rep(i,n) cin >> a[i];
    reverse(all(a));
    comInit();
    int cnt = 0;
    mint ans = 1;
    rep(i,n){
        mint mul = modpow(2,n-i-1,mod);
        mul *= mul;
        mul = modpow(mul.value(),a[i],mod);
        mul *= comb(modpow(2,i,mod) - cnt, a[i]);
        cnt += 2 * a[i];
        ans *= mul;
    }
    cout << ans.value() << "\n";
}
accuracy: 0.7435897435897436
time_ms: 10
memory_kb: 14548
final_rank: 10

code_snippet: #include <iostream>
#include <string>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <unordered_map>
#include <map>
#include <set>
#include <algorithm>
#include <queue>
#include <stack>
#include <functional>
#include <bitset>
#include <assert.h>
#include <unordered_map>
#include <fstream>
#include <ctime>
#include <complex>
//#include <atcoder/all>
using namespace std;
//using namespace atcoder;
typedef long long ll;
typedef vector<ll> vl;
typedef vector<vl> vvl;
typedef vector<char> vc;
typedef vector<string> vs;
typedef vector<bool> vb;
typedef vector<double> vd;
typedef pair<ll,ll> P;
typedef pair<int,int> pii;
typedef vector<P> vpl;
typedef tuple<ll,ll,ll> tapu;
#define rep(i,n) for(int i=0; i<(n); i++)
#define REP(i,a,b) for(int i=(a); i<(b); i++)
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
const int inf = 1<<30;
const ll linf = 1LL<<62;
const int MAX = 510000;
ll dy[8] = {1,-1,0,0,1,-1,1,-1};
ll dx[8] = {0,0,1,-1,1,-1,-1,1};
const double pi = acos(-1);
const double eps = 1e-7;
template<typename T1,typename T2> inline bool chmin(T1 &a,T2 b){
	if(a>b){
		a = b; return true;
	}
	else return false;
}
template<typename T1,typename T2> inline bool chmax(T1 &a,T2 b){
	if(a<b){
		a = b; return true;
	}
	else return false;
}
template<typename T> inline void print(T &a){
    for(auto itr = a.begin(); itr != a.end(); itr++){
		cout << *itr << " ";
	}
    cout << "\n";
}
template<typename T1,typename T2> inline void print2(T1 a, T2 b){
	cout << "debug: " << a << " " << b << "\n";
}
template<typename T1,typename T2,typename T3> inline void print3(T1 a, T2 b, T3 c){
	cout << "debug: " << a << " " << b << " " << c << "\n";
}
void mark() {cout << "#" << "\n";}
ll pcount(ll x) {return __builtin_popcountll(x);}
//const int mod = 1e9 + 7;
const int mod = 998244353;

template <std::uint_fast64_t Modulus> class modint {
  using u64 = std::uint_fast64_t;

public:
  u64 a;

  constexpr modint(const u64 x = 0) noexcept : a(x % Modulus) {}
  constexpr u64 &value() noexcept { return a; }
  constexpr const u64 &value() const noexcept { return a; }
  constexpr modint operator+(const modint rhs) const noexcept {
    return modint(*this) += rhs;
  }
  constexpr modint operator-(const modint rhs) const noexcept {
    return modint(*this) -= rhs;
  }
  constexpr modint operator*(const modint rhs) const noexcept {
    return modint(*this) *= rhs;
  }
  constexpr modint operator/(const modint rhs) const noexcept {
    return modint(*this) /= rhs;
  }
  constexpr modint &operator+=(const modint rhs) noexcept {
    a += rhs.a;
    if (a >= Modulus) {
      a -= Modulus;
    }
    return *this;
  }
  constexpr modint &operator-=(const modint rhs) noexcept {
    if (a < rhs.a) {
      a += Modulus;
    }
    a -= rhs.a;
    return *this;
  }
  constexpr modint &operator*=(const modint rhs) noexcept {
    a = a * rhs.a % Modulus;
    return *this;
  }
  constexpr modint &operator/=(modint rhs) noexcept {
    u64 exp = Modulus - 2;
    while (exp) {
      if (exp % 2) {
        *this *= rhs;
      }
      rhs *= rhs;
      exp /= 2;
    }
    return *this;
  }
};

using mint = modint<mod>;

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

vector<ll> fac(MAX), finv(MAX), inv(MAX);

void comInit(){
    fac[0] = fac[1] = 1;
    finv[0] = finv[1] = 1;
    inv[1] = 1;
    for(ll i=2; i<MAX; i++){
        fac[i] = fac[i-1]*i % mod;
        inv[i] = mod - inv[mod%i] * (mod/i) % mod;
        finv[i] = finv[i-1] * inv[i] % mod;
    }
}


ll com(ll n, ll k){
    if(n < k) return 0;
    if(n < 0 || k < 0) return 0;
    return fac[n] * (finv[k] * finv[n-k] % mod) % mod;
}

mint comb(ll n, ll k){
    if(n < 0) return 0;
    if(n == 0) return k == 0; 
    mint res = 1;
    rep(i,k){
        res *= n-i;
    }
    return res;
}

int main(){
    int n; cin >> n;
    vl a(n); rep(i,n) cin >> a[i];
    reverse(all(a));
    comInit();
    int cnt = 0;
    mint ans = 1;
    rep(i,n){
        mint mul = modpow(2,n-i-1,mod);
        mul *= mul;
        mul = modpow(mul.value(),a[i],mod);
        mul *= comb(modpow(2,i,mod) - cnt, a[i]);
        cnt += 2 * a[i];
        ans *= mul;
    }
    cout << ans.value() << "\n";
}
accuracy: 0.7435897435897436
time_ms: 10
memory_kb: 14552
final_rank: 11

code_snippet: #include<iostream>
#include<vector>
#include<string>

using namespace std;

#define int long long
#define endl "\n"

constexpr int MOD = 998244353;

long long power(long long x, long long n){
  long long ans = 1;
  for(;n;n >>= 1, x *= x, ans %= MOD, x %= MOD)
    if(n&1)ans*=x;
  return ans % MOD;
}

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

  int n;
  vector<int> con;
  vector<int> con2;
  vector<int> a;
  int ans = 1;

  cin>>n;

  con.resize(n+1);
  con2.resize(n+1);
  a.resize(n+1);

  for(int i = 1; i <= n; i++){
    cin>>a[i];
  }

  con[n]++;
  con2[n]++;

  bool flag = false;


  for(int i = n; i >= 1; i--){

    if(con2[i] > MOD) flag = true;

    if(flag == false && con2[i] < a[i]) {
      cout<<0<<endl;
      return 0;
    }

    int hoge = con[i];
    int t = power(2, (i-1)*2);

    for(int j = 0; j < a[i]; j++){
      ans *= hoge * t %MOD;
      ans %= MOD;

      hoge = (hoge + MOD - 1) % MOD;
    }

    con[i-1] += (con[i] + MOD - a[i]) * 2 % MOD;
    con2[i-1] += (con2[i] - a[i]) * 2;

    for(int j = i-2; j >= 1; j--){
      con[j] += a[i] * 2;
      con[j] %= MOD;

      con2[j] += a[i] * 2;
    }

    //cout<<"i = "<<i<<" ans = "<<ans<<endl;
  }

  cout<<ans<<endl;

  return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 3284
final_rank: 2

code_snippet: #include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/detail/standard_policies.hpp>

const double pi = 3.141592653589793238462643383279;
using namespace std;
using namespace __gnu_pbds;
//typedef
//------------------------------------------
typedef vector<int> VI;
typedef vector<VI> VVI;
typedef vector<string> VS;
typedef pair<int, int> PII;
typedef pair<long long, long long> PLL;
typedef pair<int, PII> TIII;
typedef long long LL;
typedef unsigned long long ULL;
typedef vector<LL> VLL;
typedef vector<VLL> VVLL;
 
 
//container util
//------------------------------------------
#define ALL(a)  (a).begin(),(a).end()
#define RALL(a) (a).rbegin(), (a).rend()
#define PB push_back
#define MP make_pair
#define SQ(a) ((a)*(a))
#define EACH(i,c) for(typeof((c).begin()) i=(c).begin(); i!=(c).end(); ++i)
#define EXIST(s,e) ((s).find(e)!=(s).end())
#define SORT(c) sort((c).begin(),(c).end())
 
 
//repetition
//------------------------------------------
#define FOR(i,s,n) for(int i=s;i<(int)n;++i)
#define REP(i,n) FOR(i,0,n)
#define MOD 1000000007
 
 
#define rep(i, a, b) for(int i = a; i < (b); ++i)
#define trav(a, x) for(auto& a : x)
#define all(x) x.begin(), x.end()
#define sz(x) (int)(x).size()
 
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
 
#define chmin(x,y) x=min(x,y)
#define chmax(x,y) x=max(x,y)

const long double EPS = 1e-6, PI = acos((long double)-1);

//ここから編集
ll modPow(ll x, ll n, ll mod = MOD){
    ll res = 1;
    while(n){
        if(n&1) res = (res * x)%mod;
 
        res %= mod;
        x = x * x %mod;
        n >>= 1;
    }
    return res;
}
const int MOD2 = 998244353;
const int MAX = 2000010;
long long fac[MAX], finv[MAX], inv[MAX];
 
// テーブルを作る前処理
void COMinit() {
    fac[0] = fac[1] = 1;
    finv[0] = finv[1] = 1;
    inv[1] = 1;
    for (int i = 2; i < MAX; i++){
        fac[i] = fac[i - 1] * i % MOD2;
        inv[i] = MOD2 - inv[MOD2%i] * (MOD2 / i) % MOD2;
        finv[i] = finv[i - 1] * inv[i] % MOD2;
    }
}
 
// 二項係数計算
long long COM(int n, int k){
    if (n < k) return 0;
    if (n < 0 || k < 0) return 0;
    return fac[n] * (finv[k] * finv[n - k] % MOD2) % MOD2;
}
long long extGCD(long long a, long long b, long long &x, long long &y) {
    if (b == 0) {
        x = 1;
        y = 0;
        return a;
    }
    long long d = extGCD(b, a%b, y, x);
    y -= a/b * x;
    return d;
}
// 負の数にも対応した mod (a = -11 とかでも OK) 
inline long long mod(long long a, long long m) {
    return (a % m + m) % m;
}
 
// 逆元計算 (ここでは a と m が互いに素であることが必要)
long long modinv(long long a, long long m) {
    long long x, y;
    extGCD(a, m, x, y);
    return mod(x, m); // 気持ち的には x % m だが、x が負かもしれないので
}

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

 ll N; cin >> N;

  vector<ll> a(N);
  REP(i,N) cin >> a[i];

  ll ans = 1;
  vector<ll> mx(N);
  mx[N-1] = 1;
  COMinit();
  for(int i=N-2; i>=0; i--){
    mx[i] = mx[i+1] * 2 % MOD2;
  }

  ll sa = 0;
  for(int i=N-1; i>=0; i--){
    
    if(a[i] == 0) continue;


    ll v = 1;
    for(int j=N-1; j>i; j--){
      v *= 2;
      if(v > 1000000000) break;

    }
    
    if(a[i] > v-sa){
      cout << 0 << endl;
      return 0;
    }
    
    /* n = mx[i], k = a[i] */
    ll tmp = 1;
    for(int j=0; j<a[i]; j++){
      tmp *= (mx[i]-j + MOD2)%MOD2;
      tmp %= MOD2;
    }
    for(int j=2; j<=a[i]; j++){
      tmp *= modinv(j, MOD2);
      tmp %= MOD2;
    }

    ans = (ans * tmp %MOD2 * fac[a[i]] % MOD2 * modPow(modPow(4, i, MOD2), a[i], MOD2)) % MOD2;
    
    for(int j=0; j<i; j++){
      mx[j] = (mx[j] - 2*a[i] + MOD2) % MOD2;
      
    }
    sa += 2*a[i];
  }
  cout << ans << endl;

  return 0;
}
accuracy: 1
time_ms: 190
memory_kb: 50336
final_rank: 9

code_snippet: #include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/detail/standard_policies.hpp>

const double pi = 3.141592653589793238462643383279;
using namespace std;
using namespace __gnu_pbds;
//typedef
//------------------------------------------
typedef vector<int> VI;
typedef vector<VI> VVI;
typedef vector<string> VS;
typedef pair<int, int> PII;
typedef pair<long long, long long> PLL;
typedef pair<int, PII> TIII;
typedef long long LL;
typedef unsigned long long ULL;
typedef vector<LL> VLL;
typedef vector<VLL> VVLL;
 
 
//container util
//------------------------------------------
#define ALL(a)  (a).begin(),(a).end()
#define RALL(a) (a).rbegin(), (a).rend()
#define PB push_back
#define MP make_pair
#define SQ(a) ((a)*(a))
#define EACH(i,c) for(typeof((c).begin()) i=(c).begin(); i!=(c).end(); ++i)
#define EXIST(s,e) ((s).find(e)!=(s).end())
#define SORT(c) sort((c).begin(),(c).end())
 
 
//repetition
//------------------------------------------
#define FOR(i,s,n) for(int i=s;i<(int)n;++i)
#define REP(i,n) FOR(i,0,n)
#define MOD 1000000007
 
 
#define rep(i, a, b) for(int i = a; i < (b); ++i)
#define trav(a, x) for(auto& a : x)
#define all(x) x.begin(), x.end()
#define sz(x) (int)(x).size()
 
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
 
#define chmin(x,y) x=min(x,y)
#define chmax(x,y) x=max(x,y)

const long double EPS = 1e-6, PI = acos((long double)-1);

//ここから編集
ll modPow(ll x, ll n, ll mod = MOD){
    ll res = 1;
    while(n){
        if(n&1) res = (res * x)%mod;
 
        res %= mod;
        x = x * x %mod;
        n >>= 1;
    }
    return res;
}
const int MOD2 = 998244353;
const int MAX = 2000010;
long long fac[MAX], finv[MAX], inv[MAX];
 
// テーブルを作る前処理
void COMinit() {
    fac[0] = fac[1] = 1;
    finv[0] = finv[1] = 1;
    inv[1] = 1;
    for (int i = 2; i < MAX; i++){
        fac[i] = fac[i - 1] * i % MOD2;
        inv[i] = MOD2 - inv[MOD2%i] * (MOD2 / i) % MOD2;
        finv[i] = finv[i - 1] * inv[i] % MOD2;
    }
}
 
// 二項係数計算
long long COM(int n, int k){
    if (n < k) return 0;
    if (n < 0 || k < 0) return 0;
    return fac[n] * (finv[k] * finv[n - k] % MOD2) % MOD2;
}
long long extGCD(long long a, long long b, long long &x, long long &y) {
    if (b == 0) {
        x = 1;
        y = 0;
        return a;
    }
    long long d = extGCD(b, a%b, y, x);
    y -= a/b * x;
    return d;
}
// 負の数にも対応した mod (a = -11 とかでも OK) 
inline long long mod(long long a, long long m) {
    return (a % m + m) % m;
}
 
// 逆元計算 (ここでは a と m が互いに素であることが必要)
long long modinv(long long a, long long m) {
    long long x, y;
    extGCD(a, m, x, y);
    return mod(x, m); // 気持ち的には x % m だが、x が負かもしれないので
}

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

 ll N; cin >> N;

  vector<ll> a(N);
  REP(i,N) cin >> a[i];

  ll ans = 1;
  vector<ll> mx(N);
  mx[N-1] = 1;
  COMinit();
  for(int i=N-2; i>=0; i--){
    mx[i] = mx[i+1] * 2 % MOD2;
  }

  ll sa = 0;
  for(int i=N-1; i>=0; i--){
    
    if(a[i] == 0) continue;


    ll v = 1;
    for(int j=N-1; j>i; j--){
      v *= 2;
      if(v > 1000000000) break;

    }
    
    if(a[i] > v-sa){
      cout << 0 << endl;
      return 0;
    }
    
    /* n = mx[i], k = a[i] */
    ll tmp = 1;
    for(int j=0; j<a[i]; j++){
      tmp *= (mx[i]-j + MOD2)%MOD2;
      tmp %= MOD2;
    }
    for(int j=2; j<=a[i]; j++){
      tmp *= modinv(j, MOD2);
      tmp %= MOD2;
    }

    ans = (ans * tmp * fac[a[i]]% MOD2 * modPow(modPow(4, i, MOD2), a[i], MOD2)) % MOD2;
    
    for(int j=0; j<i; j++){
      mx[j] = (mx[j] - 2*a[i] + MOD2) % MOD2;
      
    }
    sa += 2*a[i];
  }
  cout << ans << endl;

  return 0;
}
accuracy: 0.48717948717948717
time_ms: 20
memory_kb: 50352
final_rank: 17

code_snippet: #include "bits/stdc++.h"

//#include <atcoder/all>

using namespace std;
//using namespace atcoder;

//#define int long long
#define ll long long

ll INF = (1LL << 60);
int mod = 998244353;
using P = pair<int, int>;


struct mint {
	ll x; // typedef long long ll;
	mint(ll x = 0) :x((x%mod + mod) % mod) {}
	mint operator-() const { return mint(-x); }
	mint& operator+=(const mint a) {
		if ((x += a.x) >= mod) x -= mod;
		return *this;
	}
	mint& operator-=(const mint a) {
		if ((x += mod - a.x) >= mod) x -= mod;
		return *this;
	}
	mint& operator*=(const mint a) {
		(x *= a.x) %= mod;
		return *this;
	}
	mint operator+(const mint a) const {
		mint res(*this);
		return res += a;
	}
	mint operator-(const mint a) const {
		mint res(*this);
		return res -= a;
	}
	mint operator*(const mint a) const {
		mint res(*this);
		return res *= a;
	}
	mint pow(ll t) const {
		if (!t) return 1;
		mint a = pow(t >> 1);
		a *= a;
		if (t & 1) a *= *this;
		return a;
	}

	// for prime mod
	mint inv() const {
		return pow(mod - 2);
	}
	mint& operator/=(const mint a) {
		return (*this) *= a.inv();
	}
	mint operator/(const mint a) const {
		mint res(*this);
		return res /= a;
	}
};
istream& operator>>(istream& is, mint& a) { return is >> a.x; }
ostream& operator<<(ostream& os, const mint& a) { return os << a.x; }

signed main() {
	int n; cin >> n;
	vector<int>a(n); for (int i = 0; i < n; i++)cin >> a[i];
	vector<mint>cnt(n);
	cnt[n - 1] = 1;
	vector<bool>ok(n);
	mint ans = 1;
	for (int i = n - 1; i >= 0; i--) {
		if (!ok[i] && cnt[i].x < a[i]) {
			ans = 0;
			break;
		}
		for (int j = 0; j < a[i]; j++) {
			ans *= cnt[i] - j;
		}
		ans *= mint(2).pow(2 * i*a[i]);
		for (int j = 0; j < i - 1; j++) {
			if (!ok[j]) {
				if (cnt[j].x + a[i] * 2 >= mod)ok[j] = true;

			}
			cnt[j] += a[i] * 2;
		}
		cnt[i] -= a[i];
		if (i) {
			if (ok[i])ok[i - 1] = true;
			else {
				if (cnt[i - 1].x + cnt[i].x * 2 >= mod)ok[i - 1] = true;
				
			}
			cnt[i - 1] += cnt[i].x * 2;
		}
	}
	cout << ans << endl;
	return 0;
}
accuracy: 1
time_ms: 50
memory_kb: 3156
final_rank: 6

code_snippet: #include "bits/stdc++.h"

//#include <atcoder/all>

using namespace std;
//using namespace atcoder;

//#define int long long
#define ll long long

ll INF = (1LL << 60);
int mod = 998244353;
using P = pair<int, int>;


struct mint {
	ll x; // typedef long long ll;
	mint(ll x = 0) :x((x%mod + mod) % mod) {}
	mint operator-() const { return mint(-x); }
	mint& operator+=(const mint a) {
		if ((x += a.x) >= mod) x -= mod;
		return *this;
	}
	mint& operator-=(const mint a) {
		if ((x += mod - a.x) >= mod) x -= mod;
		return *this;
	}
	mint& operator*=(const mint a) {
		(x *= a.x) %= mod;
		return *this;
	}
	mint operator+(const mint a) const {
		mint res(*this);
		return res += a;
	}
	mint operator-(const mint a) const {
		mint res(*this);
		return res -= a;
	}
	mint operator*(const mint a) const {
		mint res(*this);
		return res *= a;
	}
	mint pow(ll t) const {
		if (!t) return 1;
		mint a = pow(t >> 1);
		a *= a;
		if (t & 1) a *= *this;
		return a;
	}

	// for prime mod
	mint inv() const {
		return pow(mod - 2);
	}
	mint& operator/=(const mint a) {
		return (*this) *= a.inv();
	}
	mint operator/(const mint a) const {
		mint res(*this);
		return res /= a;
	}
};
istream& operator>>(istream& is, mint& a) { return is >> a.x; }
ostream& operator<<(ostream& os, const mint& a) { return os << a.x; }

signed main() {
	int n; cin >> n;
	vector<int>a(n); for (int i = 0; i < n; i++)cin >> a[i];
	vector<mint>cnt(n);
	cnt[n - 1] = 1;
	vector<bool>ok(n);
	mint ans = 1;
	for (int i = n - 1; i >= 0; i--) {
		if (!ok[i] && cnt[i].x < a[i]) {
			ans = 0;
			break;
		}
		for (int j = 0; j < a[i]; j++) {
			ans *= cnt[i] - j;
		}
		ans *= mint(2).pow(2 * i*a[i]);
		for (int j = 0; j < i - 1; j++) {
			if (!ok[j]) {
				if (cnt[j].x + a[i] * 2 >= mod)ok[j] = true;
				cnt[j] += a[i] * 2;
			}
		}
		cnt[i] -= a[i];
		if (i) {
			if (ok[i])ok[i - 1] = true;
			else {
				if (cnt[i - 1].x + cnt[i].x * 2 >= mod)ok[i - 1] = true;
				cnt[i - 1] += cnt[i].x * 2;
			}
		}
	}
	cout << ans << endl;
	return 0;
}
accuracy: 0.2564102564102564
time_ms: 20
memory_kb: 3140
final_rank: 18

code_snippet: #include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/detail/standard_policies.hpp>

const double pi = 3.141592653589793238462643383279;
using namespace std;
using namespace __gnu_pbds;
//typedef
//------------------------------------------
typedef vector<int> VI;
typedef vector<VI> VVI;
typedef vector<string> VS;
typedef pair<int, int> PII;
typedef pair<long long, long long> PLL;
typedef pair<int, PII> TIII;
typedef long long LL;
typedef unsigned long long ULL;
typedef vector<LL> VLL;
typedef vector<VLL> VVLL;
 
 
//container util
//------------------------------------------
#define ALL(a)  (a).begin(),(a).end()
#define RALL(a) (a).rbegin(), (a).rend()
#define PB push_back
#define MP make_pair
#define SQ(a) ((a)*(a))
#define EACH(i,c) for(typeof((c).begin()) i=(c).begin(); i!=(c).end(); ++i)
#define EXIST(s,e) ((s).find(e)!=(s).end())
#define SORT(c) sort((c).begin(),(c).end())
 
 
//repetition
//------------------------------------------
#define FOR(i,s,n) for(int i=s;i<(int)n;++i)
#define REP(i,n) FOR(i,0,n)
#define MOD 1000000007
 
 
#define rep(i, a, b) for(int i = a; i < (b); ++i)
#define trav(a, x) for(auto& a : x)
#define all(x) x.begin(), x.end()
#define sz(x) (int)(x).size()
 
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
 
#define chmin(x,y) x=min(x,y)
#define chmax(x,y) x=max(x,y)

const long double EPS = 1e-6, PI = acos((long double)-1);

//ここから編集
ll modPow(ll x, ll n, ll mod = MOD){
    ll res = 1;
    while(n){
        if(n&1) res = (res * x)%mod;
 
        res %= mod;
        x = x * x %mod;
        n >>= 1;
    }
    return res;
}
const int MOD2 = 998244353;
const int MAX = 2000010;
long long fac[MAX], finv[MAX], inv[MAX];
 
// テーブルを作る前処理
void COMinit() {
    fac[0] = fac[1] = 1;
    finv[0] = finv[1] = 1;
    inv[1] = 1;
    for (int i = 2; i < MAX; i++){
        fac[i] = fac[i - 1] * i % MOD2;
        inv[i] = MOD2 - inv[MOD2%i] * (MOD2 / i) % MOD2;
        finv[i] = finv[i - 1] * inv[i] % MOD2;
    }
}
 
// 二項係数計算
long long COM(int n, int k){
    if (n < k) return 0;
    if (n < 0 || k < 0) return 0;
    return fac[n] * (finv[k] * finv[n - k] % MOD2) % MOD2;
}
long long extGCD(long long a, long long b, long long &x, long long &y) {
    if (b == 0) {
        x = 1;
        y = 0;
        return a;
    }
    long long d = extGCD(b, a%b, y, x);
    y -= a/b * x;
    return d;
}
// 負の数にも対応した mod (a = -11 とかでも OK) 
inline long long mod(long long a, long long m) {
    return (a % m + m) % m;
}
 
// 逆元計算 (ここでは a と m が互いに素であることが必要)
long long modinv(long long a, long long m) {
    long long x, y;
    extGCD(a, m, x, y);
    return mod(x, m); // 気持ち的には x % m だが、x が負かもしれないので
}

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

 ll N; cin >> N;

  vector<ll> a(N);
  REP(i,N) cin >> a[i];

  ll ans = 1;
  vector<ll> mx(N);
  mx[N-1] = 1;
  COMinit();
  for(int i=N-2; i>=0; i--){
    mx[i] = mx[i+1] * 2 % MOD2;
  }

  ll sa = 0;
  for(int i=N-1; i>=0; i--){
    
    if(a[i] == 0) continue;


    ll v = 1;
    for(int j=i; j<N-1; j++){
      v *= 2;
      if(v > 1000000000) break;

    }
    
    if(a[i] > v-sa){
      cout << 0 << endl;
      return 0;
    }
    
    /* n = mx[i], k = a[i] */
    ll tmp = 1;
    for(int j=0; j<a[i]; j++){
      tmp *= (mx[i]-j + MOD2)%MOD2;
      tmp %= MOD2;
    }
    for(int j=2; j<=a[i]; j++){
      tmp *= modinv(j, MOD2);
      tmp %= MOD2;
    }

    ans = (ans * tmp % MOD2 * fac[a[i]] % MOD2 *  modPow(4, i, MOD2)) % MOD2;
    
    for(int j=0; j<i; j++){
      mx[j] = (mx[j] - 2*a[i] + MOD2) % MOD2;
      
    }
    sa += 2*a[i];
  }
  cout << ans << endl;

  return 0;
}
accuracy: 0.48717948717948717
time_ms: 20
memory_kb: 50348
final_rank: 15

code_snippet: #include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/detail/standard_policies.hpp>

const double pi = 3.141592653589793238462643383279;
using namespace std;
using namespace __gnu_pbds;
//typedef
//------------------------------------------
typedef vector<int> VI;
typedef vector<VI> VVI;
typedef vector<string> VS;
typedef pair<int, int> PII;
typedef pair<long long, long long> PLL;
typedef pair<int, PII> TIII;
typedef long long LL;
typedef unsigned long long ULL;
typedef vector<LL> VLL;
typedef vector<VLL> VVLL;
 
 
//container util
//------------------------------------------
#define ALL(a)  (a).begin(),(a).end()
#define RALL(a) (a).rbegin(), (a).rend()
#define PB push_back
#define MP make_pair
#define SQ(a) ((a)*(a))
#define EACH(i,c) for(typeof((c).begin()) i=(c).begin(); i!=(c).end(); ++i)
#define EXIST(s,e) ((s).find(e)!=(s).end())
#define SORT(c) sort((c).begin(),(c).end())
 
 
//repetition
//------------------------------------------
#define FOR(i,s,n) for(int i=s;i<(int)n;++i)
#define REP(i,n) FOR(i,0,n)
#define MOD 1000000007
 
 
#define rep(i, a, b) for(int i = a; i < (b); ++i)
#define trav(a, x) for(auto& a : x)
#define all(x) x.begin(), x.end()
#define sz(x) (int)(x).size()
 
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
 
#define chmin(x,y) x=min(x,y)
#define chmax(x,y) x=max(x,y)

const long double EPS = 1e-6, PI = acos((long double)-1);

//ここから編集
ll modPow(ll x, ll n, ll mod = MOD){
    ll res = 1;
    while(n){
        if(n&1) res = (res * x)%mod;
 
        res %= mod;
        x = x * x %mod;
        n >>= 1;
    }
    return res;
}
const int MOD2 = 998244353;
const int MAX = 2000010;
long long fac[MAX], finv[MAX], inv[MAX];
 
// テーブルを作る前処理
void COMinit() {
    fac[0] = fac[1] = 1;
    finv[0] = finv[1] = 1;
    inv[1] = 1;
    for (int i = 2; i < MAX; i++){
        fac[i] = fac[i - 1] * i % MOD2;
        inv[i] = MOD2 - inv[MOD2%i] * (MOD2 / i) % MOD2;
        finv[i] = finv[i - 1] * inv[i] % MOD2;
    }
}
 
// 二項係数計算
long long COM(int n, int k){
    if (n < k) return 0;
    if (n < 0 || k < 0) return 0;
    return fac[n] * (finv[k] * finv[n - k] % MOD2) % MOD2;
}
long long extGCD(long long a, long long b, long long &x, long long &y) {
    if (b == 0) {
        x = 1;
        y = 0;
        return a;
    }
    long long d = extGCD(b, a%b, y, x);
    y -= a/b * x;
    return d;
}
// 負の数にも対応した mod (a = -11 とかでも OK) 
inline long long mod(long long a, long long m) {
    return (a % m + m) % m;
}
 
// 逆元計算 (ここでは a と m が互いに素であることが必要)
long long modinv(long long a, long long m) {
    long long x, y;
    extGCD(a, m, x, y);
    return mod(x, m); // 気持ち的には x % m だが、x が負かもしれないので
}

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

 ll N; cin >> N;

  vector<ll> a(N);
  REP(i,N) cin >> a[i];

  ll ans = 1;
  vector<ll> mx(N);
  mx[N-1] = 1;
  COMinit();
  for(int i=N-2; i>=0; i--){
    mx[i] = mx[i+1] * 2 % MOD2;
  }

  ll sa = 0;
  for(int i=N-1; i>=0; i--){
    
    if(a[i] == 0) continue;

    bool check = false;
    ll v = 1;
    for(int j=i; j<N-1; j++){
      v *= 2;
      if(v > N*2000) break;

    }
    
    if(a[i] > v-sa){
      cout << 0 << endl;
      return 0;
    }
    
    /* n = mx[i], k = a[i] */
    ll tmp = 1;
    for(int j=0; j<a[i]; j++){
      tmp *= (mx[i]-j + MOD2)%MOD2;
      tmp %= MOD2;
    }
    for(int j=2; j<=a[i]; j++){
      tmp *= modinv(j, MOD2);
      tmp %= MOD2;
    }

    ans = (ans * tmp % MOD2 * fac[a[i]] % MOD2 *  modPow(4, i, MOD2)) % MOD2;
    
    for(int j=0; j<i; j++){
      mx[j] = (mx[j] - 2*a[i] + MOD2) % MOD2;
      
    }
    sa += 2*a[i];
  }
  cout << ans << endl;

  return 0;
}
accuracy: 0.48717948717948717
time_ms: 20
memory_kb: 50332
final_rank: 12

code_snippet: #include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/detail/standard_policies.hpp>

const double pi = 3.141592653589793238462643383279;
using namespace std;
using namespace __gnu_pbds;
//typedef
//------------------------------------------
typedef vector<int> VI;
typedef vector<VI> VVI;
typedef vector<string> VS;
typedef pair<int, int> PII;
typedef pair<long long, long long> PLL;
typedef pair<int, PII> TIII;
typedef long long LL;
typedef unsigned long long ULL;
typedef vector<LL> VLL;
typedef vector<VLL> VVLL;
 
 
//container util
//------------------------------------------
#define ALL(a)  (a).begin(),(a).end()
#define RALL(a) (a).rbegin(), (a).rend()
#define PB push_back
#define MP make_pair
#define SQ(a) ((a)*(a))
#define EACH(i,c) for(typeof((c).begin()) i=(c).begin(); i!=(c).end(); ++i)
#define EXIST(s,e) ((s).find(e)!=(s).end())
#define SORT(c) sort((c).begin(),(c).end())
 
 
//repetition
//------------------------------------------
#define FOR(i,s,n) for(int i=s;i<(int)n;++i)
#define REP(i,n) FOR(i,0,n)
#define MOD 1000000007
 
 
#define rep(i, a, b) for(int i = a; i < (b); ++i)
#define trav(a, x) for(auto& a : x)
#define all(x) x.begin(), x.end()
#define sz(x) (int)(x).size()
 
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
 
#define chmin(x,y) x=min(x,y)
#define chmax(x,y) x=max(x,y)

const long double EPS = 1e-6, PI = acos((long double)-1);

//ここから編集
ll modPow(ll x, ll n, ll mod = MOD){
    ll res = 1;
    while(n){
        if(n&1) res = (res * x)%mod;
 
        res %= mod;
        x = x * x %mod;
        n >>= 1;
    }
    return res;
}
const int MOD2 = 998244353;
const int MAX = 2000010;
long long fac[MAX], finv[MAX], inv[MAX];
 
// テーブルを作る前処理
void COMinit() {
    fac[0] = fac[1] = 1;
    finv[0] = finv[1] = 1;
    inv[1] = 1;
    for (int i = 2; i < MAX; i++){
        fac[i] = fac[i - 1] * i % MOD2;
        inv[i] = MOD2 - inv[MOD2%i] * (MOD2 / i) % MOD2;
        finv[i] = finv[i - 1] * inv[i] % MOD2;
    }
}
 
// 二項係数計算
long long COM(int n, int k){
    if (n < k) return 0;
    if (n < 0 || k < 0) return 0;
    return fac[n] * (finv[k] * finv[n - k] % MOD2) % MOD2;
}
long long extGCD(long long a, long long b, long long &x, long long &y) {
    if (b == 0) {
        x = 1;
        y = 0;
        return a;
    }
    long long d = extGCD(b, a%b, y, x);
    y -= a/b * x;
    return d;
}
// 負の数にも対応した mod (a = -11 とかでも OK) 
inline long long mod(long long a, long long m) {
    return (a % m + m) % m;
}
 
// 逆元計算 (ここでは a と m が互いに素であることが必要)
long long modinv(long long a, long long m) {
    long long x, y;
    extGCD(a, m, x, y);
    return mod(x, m); // 気持ち的には x % m だが、x が負かもしれないので
}

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

  int N; cin >> N;

  vector<ll> a(N);
  REP(i,N) cin >> a[i];

  ll ans = 1;
  vector<ll> mx(N);
  mx[N-1] = 1;
  COMinit();
  for(int i=N-2; i>=0; i--){
    mx[i] = mx[i+1] * 2 % MOD2;
  }

  for(int i=N-1; i>=0; i--){
    
if(a[i] == 0) continue;
    if(a[i] > mx[i]){
      cout << 0 << endl;
      return 0;
    }
    
    /* n = mx[i], k = a[i] */
    ll tmp = 1;
    for(int j=0; j<a[i]; j++){
      tmp *= (mx[i]-j + MOD2)%MOD2;
      tmp %= MOD2;
    }
    for(int j=2; j<=a[i]; j++){
      tmp *= modinv(j, MOD2);
      tmp %= MOD2;
    }

    ans = (ans * tmp % MOD2 * fac[a[i]] % MOD2 *  modPow(4, i, MOD2)) % MOD2;
    
    for(int j=0; j<i; j++){
      mx[j] = (mx[j] - 2*a[i] + MOD2) % MOD2;
      
    }
  }
  cout << ans << endl;

  return 0;
}
accuracy: 0.48717948717948717
time_ms: 20
memory_kb: 50336
final_rank: 13

code_snippet: #include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/detail/standard_policies.hpp>

const double pi = 3.141592653589793238462643383279;
using namespace std;
using namespace __gnu_pbds;
//typedef
//------------------------------------------
typedef vector<int> VI;
typedef vector<VI> VVI;
typedef vector<string> VS;
typedef pair<int, int> PII;
typedef pair<long long, long long> PLL;
typedef pair<int, PII> TIII;
typedef long long LL;
typedef unsigned long long ULL;
typedef vector<LL> VLL;
typedef vector<VLL> VVLL;
 
 
//container util
//------------------------------------------
#define ALL(a)  (a).begin(),(a).end()
#define RALL(a) (a).rbegin(), (a).rend()
#define PB push_back
#define MP make_pair
#define SQ(a) ((a)*(a))
#define EACH(i,c) for(typeof((c).begin()) i=(c).begin(); i!=(c).end(); ++i)
#define EXIST(s,e) ((s).find(e)!=(s).end())
#define SORT(c) sort((c).begin(),(c).end())
 
 
//repetition
//------------------------------------------
#define FOR(i,s,n) for(int i=s;i<(int)n;++i)
#define REP(i,n) FOR(i,0,n)
#define MOD 1000000007
 
 
#define rep(i, a, b) for(int i = a; i < (b); ++i)
#define trav(a, x) for(auto& a : x)
#define all(x) x.begin(), x.end()
#define sz(x) (int)(x).size()
 
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
 
#define chmin(x,y) x=min(x,y)
#define chmax(x,y) x=max(x,y)

const long double EPS = 1e-6, PI = acos((long double)-1);

//ここから編集
ll modPow(ll x, ll n, ll mod = MOD){
    ll res = 1;
    while(n){
        if(n&1) res = (res * x)%mod;
 
        res %= mod;
        x = x * x %mod;
        n >>= 1;
    }
    return res;
}
const int MOD2 = 998244353;
const int MAX = 2000010;
long long fac[MAX], finv[MAX], inv[MAX];
 
// テーブルを作る前処理
void COMinit() {
    fac[0] = fac[1] = 1;
    finv[0] = finv[1] = 1;
    inv[1] = 1;
    for (int i = 2; i < MAX; i++){
        fac[i] = fac[i - 1] * i % MOD2;
        inv[i] = MOD2 - inv[MOD2%i] * (MOD2 / i) % MOD2;
        finv[i] = finv[i - 1] * inv[i] % MOD2;
    }
}
 
// 二項係数計算
long long COM(int n, int k){
    if (n < k) return 0;
    if (n < 0 || k < 0) return 0;
    return fac[n] * (finv[k] * finv[n - k] % MOD2) % MOD2;
}
long long extGCD(long long a, long long b, long long &x, long long &y) {
    if (b == 0) {
        x = 1;
        y = 0;
        return a;
    }
    long long d = extGCD(b, a%b, y, x);
    y -= a/b * x;
    return d;
}
// 負の数にも対応した mod (a = -11 とかでも OK) 
inline long long mod(long long a, long long m) {
    return (a % m + m) % m;
}
 
// 逆元計算 (ここでは a と m が互いに素であることが必要)
long long modinv(long long a, long long m) {
    long long x, y;
    extGCD(a, m, x, y);
    return mod(x, m); // 気持ち的には x % m だが、x が負かもしれないので
}

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

  int N; cin >> N;

  vector<ll> a(N);
  REP(i,N) cin >> a[i];

  ll ans = 1;
  vector<ll> mx(N);
  mx[N-1] = 1;
  COMinit();
  for(int i=N-2; i>=0; i--){
    mx[i] = mx[i+1] * 2 % MOD2;
  }

  for(int i=N-1; i>=0; i--){
    

    if(a[i] > mx[i]){
      cout << 0 << endl;
      return 0;
    }
    if(a[i] == 0) continue;
    /* n = mx[i], k = a[i] */
    ll tmp = 1;
    for(int j=0; j<a[i]; j++){
      tmp *= (mx[i]-j + MOD2)%MOD2;
      tmp %= MOD2;
    }
    for(int j=2; j<=a[i]; j++){
      tmp *= modinv(j, MOD2);
      tmp %= MOD2;
    }

    ans = (ans * tmp % MOD2 * fac[a[i]] % MOD2 *  modPow(4, i, MOD2)) % MOD2;
    
    for(int j=0; j<i; j++){
      mx[j] = (mx[j] - 2*a[i] + MOD2) % MOD2;
      
    }
  }
  cout << ans << endl;

  return 0;
}
accuracy: 0.48717948717948717
time_ms: 20
memory_kb: 50340
final_rank: 14

code_snippet: #include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/detail/standard_policies.hpp>

const double pi = 3.141592653589793238462643383279;
using namespace std;
using namespace __gnu_pbds;
//typedef
//------------------------------------------
typedef vector<int> VI;
typedef vector<VI> VVI;
typedef vector<string> VS;
typedef pair<int, int> PII;
typedef pair<long long, long long> PLL;
typedef pair<int, PII> TIII;
typedef long long LL;
typedef unsigned long long ULL;
typedef vector<LL> VLL;
typedef vector<VLL> VVLL;
 
 
//container util
//------------------------------------------
#define ALL(a)  (a).begin(),(a).end()
#define RALL(a) (a).rbegin(), (a).rend()
#define PB push_back
#define MP make_pair
#define SQ(a) ((a)*(a))
#define EACH(i,c) for(typeof((c).begin()) i=(c).begin(); i!=(c).end(); ++i)
#define EXIST(s,e) ((s).find(e)!=(s).end())
#define SORT(c) sort((c).begin(),(c).end())
 
 
//repetition
//------------------------------------------
#define FOR(i,s,n) for(int i=s;i<(int)n;++i)
#define REP(i,n) FOR(i,0,n)
#define MOD 1000000007
 
 
#define rep(i, a, b) for(int i = a; i < (b); ++i)
#define trav(a, x) for(auto& a : x)
#define all(x) x.begin(), x.end()
#define sz(x) (int)(x).size()
 
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
 
#define chmin(x,y) x=min(x,y)
#define chmax(x,y) x=max(x,y)

const long double EPS = 1e-6, PI = acos((long double)-1);

//ここから編集
ll modPow(ll x, ll n, ll mod = MOD){
    ll res = 1;
    while(n){
        if(n&1) res = (res * x)%mod;
 
        res %= mod;
        x = x * x %mod;
        n >>= 1;
    }
    return res;
}
const int MOD2 = 998244353;
const int MAX = 2000010;
long long fac[MAX], finv[MAX], inv[MAX];
 
// テーブルを作る前処理
void COMinit() {
    fac[0] = fac[1] = 1;
    finv[0] = finv[1] = 1;
    inv[1] = 1;
    for (int i = 2; i < MAX; i++){
        fac[i] = fac[i - 1] * i % MOD2;
        inv[i] = MOD2 - inv[MOD2%i] * (MOD2 / i) % MOD2;
        finv[i] = finv[i - 1] * inv[i] % MOD2;
    }
}
 
// 二項係数計算
long long COM(int n, int k){
    if (n < k) return 0;
    if (n < 0 || k < 0) return 0;
    return fac[n] * (finv[k] * finv[n - k] % MOD2) % MOD2;
}
long long extGCD(long long a, long long b, long long &x, long long &y) {
    if (b == 0) {
        x = 1;
        y = 0;
        return a;
    }
    long long d = extGCD(b, a%b, y, x);
    y -= a/b * x;
    return d;
}
// 負の数にも対応した mod (a = -11 とかでも OK) 
inline long long mod(long long a, long long m) {
    return (a % m + m) % m;
}
 
// 逆元計算 (ここでは a と m が互いに素であることが必要)
long long modinv(long long a, long long m) {
    long long x, y;
    extGCD(a, m, x, y);
    return mod(x, m); // 気持ち的には x % m だが、x が負かもしれないので
}

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

  int N; cin >> N;

  vector<ll> a(N);
  REP(i,N) cin >> a[i];

  ll ans = 1;
  vector<ll> mx(N);
  mx[N-1] = 1;
  COMinit();
  for(int i=N-2; i>=0; i--){
    mx[i] = mx[i+1] * 2 % MOD2;
  }

  for(int i=N-1; i>=0; i--){
    

    if(a[i] > mx[i]){
      cout << 0 << endl;
      return 0;
    }
    if(a[i] == 0) continue;
    /* n = mx[i], k = a[i] */
    ll tmp = 1;
    for(int j=0; j<a[i]; j++){
      tmp *= (mx[i]-j);
      tmp %= MOD2;
    }
    for(int j=2; j<=a[i]; j++){
      tmp *= modinv(j, MOD2);
      tmp %= MOD2;
    }
    if(i == 0){
      ans = (ans * tmp % MOD2 * fac[a[i]] % MOD2);
    }else{
      ans = (ans * tmp % MOD2 * fac[a[i]] % MOD2 *  modPow(4, i, MOD2)) % MOD2;
    }
    for(int j=0; j<i; j++){
      mx[j] = (mx[j] - 2*a[i] + MOD2) % MOD2;
      
    }
  }
  cout << ans << endl;

  return 0;
}
accuracy: 0.48717948717948717
time_ms: 20
memory_kb: 50348
final_rank: 15

code_snippet: #include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/detail/standard_policies.hpp>

const double pi = 3.141592653589793238462643383279;
using namespace std;
using namespace __gnu_pbds;
//typedef
//------------------------------------------
typedef vector<int> VI;
typedef vector<VI> VVI;
typedef vector<string> VS;
typedef pair<int, int> PII;
typedef pair<long long, long long> PLL;
typedef pair<int, PII> TIII;
typedef long long LL;
typedef unsigned long long ULL;
typedef vector<LL> VLL;
typedef vector<VLL> VVLL;
 
 
//container util
//------------------------------------------
#define ALL(a)  (a).begin(),(a).end()
#define RALL(a) (a).rbegin(), (a).rend()
#define PB push_back
#define MP make_pair
#define SQ(a) ((a)*(a))
#define EACH(i,c) for(typeof((c).begin()) i=(c).begin(); i!=(c).end(); ++i)
#define EXIST(s,e) ((s).find(e)!=(s).end())
#define SORT(c) sort((c).begin(),(c).end())
 
 
//repetition
//------------------------------------------
#define FOR(i,s,n) for(int i=s;i<(int)n;++i)
#define REP(i,n) FOR(i,0,n)
#define MOD 1000000007
 
 
#define rep(i, a, b) for(int i = a; i < (b); ++i)
#define trav(a, x) for(auto& a : x)
#define all(x) x.begin(), x.end()
#define sz(x) (int)(x).size()
 
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
 
#define chmin(x,y) x=min(x,y)
#define chmax(x,y) x=max(x,y)

const long double EPS = 1e-6, PI = acos((long double)-1);

//ここから編集
ll modPow(ll x, ll n, ll mod = MOD){
    ll res = 1;
    while(n){
        if(n&1) res = (res * x)%mod;
 
        res %= mod;
        x = x * x %mod;
        n >>= 1;
    }
    return res;
}
const int MOD2 = 998244353;
const int MAX = 2000010;
long long fac[MAX], finv[MAX], inv[MAX];
 
// テーブルを作る前処理
void COMinit() {
    fac[0] = fac[1] = 1;
    finv[0] = finv[1] = 1;
    inv[1] = 1;
    for (int i = 2; i < MAX; i++){
        fac[i] = fac[i - 1] * i % MOD2;
        inv[i] = MOD2 - inv[MOD2%i] * (MOD2 / i) % MOD2;
        finv[i] = finv[i - 1] * inv[i] % MOD2;
    }
}
 
// 二項係数計算
long long COM(int n, int k){
    if (n < k) return 0;
    if (n < 0 || k < 0) return 0;
    return fac[n] * (finv[k] * finv[n - k] % MOD2) % MOD2;
}
long long extGCD(long long a, long long b, long long &x, long long &y) {
    if (b == 0) {
        x = 1;
        y = 0;
        return a;
    }
    long long d = extGCD(b, a%b, y, x);
    y -= a/b * x;
    return d;
}
// 負の数にも対応した mod (a = -11 とかでも OK) 
inline long long mod(long long a, long long m) {
    return (a % m + m) % m;
}
 
// 逆元計算 (ここでは a と m が互いに素であることが必要)
long long modinv(long long a, long long m) {
    long long x, y;
    extGCD(a, m, x, y);
    return mod(x, m); // 気持ち的には x % m だが、x が負かもしれないので
}

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

  int N; cin >> N;

  vector<ll> a(N);
  REP(i,N) cin >> a[i];

  ll ans = 1;
  vector<ll> mx(N);
  mx[N-1] = 1;
  COMinit();
  for(int i=N-2; i>=0; i--){
    mx[i] = mx[i+1] * 2 % MOD2;
  }

  for(int i=N-1; i>=0; i--){
    

    if(a[i] > mx[i]){
      cout << 0 << endl;
      return 0;
    }
    if(a[i] == 0) continue;
    /* n = mx[i], k = a[i] */
    ll tmp = 1;
    for(int j=0; j<a[i]; j++){
      tmp *= (mx[i]-j);
      tmp %= MOD2;
    }
    for(int j=2; j<=a[i]; j++){
      tmp *= modinv(j, MOD2);
      tmp %= MOD2;
    }
    if(i == 0){
      ans = (ans * tmp % MOD2 * fac[a[i]] % MOD2);
    }else{
      ans = (ans * tmp % MOD2 * fac[a[i]] % MOD2 *  modPow(2, i+1, MOD2)) % MOD2;
    }
    for(int j=0; j<i; j++){
      mx[j] = (mx[j] - 2*a[i] + MOD2) % MOD2;
      
    }
  }
  cout << ans << endl;

  return 0;
}
accuracy: 0.2564102564102564
time_ms: 20
memory_kb: 50348
final_rank: 20

code_snippet: #include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/detail/standard_policies.hpp>

const double pi = 3.141592653589793238462643383279;
using namespace std;
using namespace __gnu_pbds;
//typedef
//------------------------------------------
typedef vector<int> VI;
typedef vector<VI> VVI;
typedef vector<string> VS;
typedef pair<int, int> PII;
typedef pair<long long, long long> PLL;
typedef pair<int, PII> TIII;
typedef long long LL;
typedef unsigned long long ULL;
typedef vector<LL> VLL;
typedef vector<VLL> VVLL;
 
 
//container util
//------------------------------------------
#define ALL(a)  (a).begin(),(a).end()
#define RALL(a) (a).rbegin(), (a).rend()
#define PB push_back
#define MP make_pair
#define SQ(a) ((a)*(a))
#define EACH(i,c) for(typeof((c).begin()) i=(c).begin(); i!=(c).end(); ++i)
#define EXIST(s,e) ((s).find(e)!=(s).end())
#define SORT(c) sort((c).begin(),(c).end())
 
 
//repetition
//------------------------------------------
#define FOR(i,s,n) for(int i=s;i<(int)n;++i)
#define REP(i,n) FOR(i,0,n)
#define MOD 1000000007
 
 
#define rep(i, a, b) for(int i = a; i < (b); ++i)
#define trav(a, x) for(auto& a : x)
#define all(x) x.begin(), x.end()
#define sz(x) (int)(x).size()
 
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
 
#define chmin(x,y) x=min(x,y)
#define chmax(x,y) x=max(x,y)

const long double EPS = 1e-6, PI = acos((long double)-1);

//ここから編集
ll modPow(ll x, ll n, ll mod = MOD){
    ll res = 1;
    while(n){
        if(n&1) res = (res * x)%mod;
 
        res %= mod;
        x = x * x %mod;
        n >>= 1;
    }
    return res;
}
const int MOD2 = 998244353;
const int MAX = 2000010;
long long fac[MAX], finv[MAX], inv[MAX];
 
// テーブルを作る前処理
void COMinit() {
    fac[0] = fac[1] = 1;
    finv[0] = finv[1] = 1;
    inv[1] = 1;
    for (int i = 2; i < MAX; i++){
        fac[i] = fac[i - 1] * i % MOD2;
        inv[i] = MOD2 - inv[MOD2%i] * (MOD2 / i) % MOD2;
        finv[i] = finv[i - 1] * inv[i] % MOD2;
    }
}
 
// 二項係数計算
long long COM(int n, int k){
    if (n < k) return 0;
    if (n < 0 || k < 0) return 0;
    return fac[n] * (finv[k] * finv[n - k] % MOD2) % MOD2;
}
long long extGCD(long long a, long long b, long long &x, long long &y) {
    if (b == 0) {
        x = 1;
        y = 0;
        return a;
    }
    long long d = extGCD(b, a%b, y, x);
    y -= a/b * x;
    return d;
}
// 負の数にも対応した mod (a = -11 とかでも OK) 
inline long long mod(long long a, long long m) {
    return (a % m + m) % m;
}
 
// 逆元計算 (ここでは a と m が互いに素であることが必要)
long long modinv(long long a, long long m) {
    long long x, y;
    extGCD(a, m, x, y);
    return mod(x, m); // 気持ち的には x % m だが、x が負かもしれないので
}

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

  int N; cin >> N;

  vector<ll> a(N);
  REP(i,N) cin >> a[i];

  ll ans = 1;
  vector<ll> mx(N);
  mx[N-1] = 1;
  COMinit();
  for(int i=N-2; i>=0; i--){
    mx[i] = mx[i+1] * 2 % MOD2;
  }
  for(int i=N-1; i>=0; i--){
    if(a[i] == 0) continue;

    if(a[i] > mx[i]){
      cout << 0 << endl;
      return 0;
    }
    /* n = mx[i], k = a[i] */
    ll tmp = 1;
    for(int j=0; j<a[i]; j++){
      tmp *= (mx[i]-j);
      tmp %= MOD2;
    }
    for(int j=2; j<=a[i]; j++){
      tmp *= modinv(j, MOD2);
      tmp %= MOD2;
    }
    if(i == 0){
      ans = (ans * tmp % MOD2 * fac[a[i]] % MOD2);
    }else{
      ans = (ans * tmp % MOD2 * fac[a[i]] % MOD2 *  modPow(2, i+1, MOD2)) % MOD2;
    }
    for(int j=0; j<i; j++){
      mx[j] = (mx[j] - 2*a[i] + MOD2) % MOD2;
      
    }
  }
  cout << ans << endl;

  return 0;
}
accuracy: 0.2564102564102564
time_ms: 20
memory_kb: 50336
final_rank: 19

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

template <int mod = (int)(998244353)>
struct ModInt {
  int x;
  ModInt() : x(0) {}
  ModInt(int64_t y) : x(y >= 0 ? y % mod : (mod - (-y) % mod) % mod) {}
  ModInt &operator+=(const ModInt &p) {
    if ((x += p.x) >= mod) x -= mod;
    return *this;
  }
  ModInt &operator-=(const ModInt &p) {
    if ((x += mod - p.x) >= mod) x -= mod;
    return *this;
  }
  ModInt &operator*=(const ModInt &p) {
    x = (int)(1LL * x * p.x % mod);
    return *this;
  }
  ModInt &operator/=(const ModInt &p) {
    *this *= p.inverse();
    return *this;
  }
  ModInt operator-() const { return ModInt(-x); }
  ModInt operator+(const ModInt &p) const { return ModInt(*this) += p; }
  ModInt operator-(const ModInt &p) const { return ModInt(*this) -= p; }
  ModInt operator*(const ModInt &p) const { return ModInt(*this) *= p; }
  ModInt operator/(const ModInt &p) const { return ModInt(*this) /= p; }
  bool operator==(const ModInt &p) const { return x == p.x; }
  bool operator!=(const ModInt &p) const { return x != p.x; }
  ModInt inverse() const {
    int a = x, b = mod, u = 1, v = 0, t;
    while (b > 0) {
      t = a / b;
      swap(a -= t * b, b);
      swap(u -= t * v, v);
    }
    return ModInt(u);
  }
  ModInt pow(int64_t n) const {
    ModInt res(1), mul(x);
    while (n) {
      if (n & 1) res *= mul;
      mul *= mul;
      n >>= 1;
    }
    return res;
  }
  friend ostream &operator<<(ostream &os, const ModInt &p) { return os << p.x; }
  friend istream &operator>>(istream &is, ModInt &a) {
    int64_t t;
    is >> t;
    a = ModInt<mod>(t);
    return (is);
  }
  static int get_mod() { return mod; }
};

struct Combination {
  vector<ModInt<>> _fact, _rfact, _inv;
  Combination(long long nsize = 5000000)
      : _fact(nsize + 1), _rfact(nsize + 1), _inv(nsize + 1) {
    _fact[0] = _rfact[nsize] = _inv[0] = 1;
    for (int i = 1; i <= nsize; i++) _fact[i] = _fact[i - 1] * i;
    _rfact[nsize] /= _fact[nsize];
    for (int i = nsize - 1; i >= 0; i--) _rfact[i] = _rfact[i + 1] * (i + 1);
    for (int i = 1; i <= nsize; i++) _inv[i] = _rfact[i] * _fact[i - 1];
  }
  inline ModInt<> fact(int k) const { return _fact[k]; }

  inline ModInt<> rfact(int k) const { return _rfact[k]; }

  inline ModInt<> inv(int k) const { return _inv[k]; }

  ModInt<> P(int n, int r) const {
    if (r < 0 || n < r) return 0;
    return fact(n) * rfact(n - r);
  }

  ModInt<> C(int p, int q) const {
    if (q < 0 || p < q) return 0;
    return fact(p) * rfact(q) * rfact(p - q);
  }

  ModInt<> largeC(long long p, long long q) const {
    if (q < 0 || p < q) return 0;
    ModInt<> res = rfact(q);
    for (int i = 0; i < q; ++i) res *= p - i;
    return res;
  }

  // n types,choose r
  ModInt<> H(int n, int r) const {
    if (n < 0 || r < 0) return (0);
    return r == 0 ? 1 : C(n + r - 1, r);
  }
};

Combination com;
int n;
vector<int> a;
vector<ModInt<>> cnt;

ModInt<> solve();

int main() {
  cin >> n;
  a.resize(n + 1);
  cnt.assign(n + 1, 0);
  for (int i = 1; i <= n; ++i) cin >> a[i];
  cout << solve() << endl;
  return 0;
}

ModInt<> solve() {
  ModInt<> res = 1;
  cnt[n] = 1;
  for (int i = n; i >= 1; --i) {
    ModInt<> now = 1, two = 2;
    for (int j = 0; j < a[i]; ++j) now *= cnt[i] - j;
    now *= two.pow((2 * i - 2) * a[i]);
    res *= now;
    cnt[i - 1] += (cnt[i] - a[i]) * 2;
    for (int j = i - 2; j > 0; --j) cnt[j] += 2 * a[i];
  }
  return res;
}
accuracy: 1
time_ms: 50
memory_kb: 61672
final_rank: 8