Problem:
C: Separate Number
問題
長さ $N$ の数列 $(A_1,\ldots,A_N)$ と 長さ $M$ の数列 $(B_1,\ldots,B_M)$ が与えられます。
数列 $A$ に対して、以下の操作 $1$, $2$ をそれぞれ任意の順番に $0$ 回以上行い、数列 $B$ に一致するような操作列が何通りあるかを出力してください。ただし、答えが非常に大きくなる可能性があるので、答えを $998244353$ で割ったあまりを出力してください。
操作 $1$ :
$1 \leq k \leq n$ を満たす整数 $k$ を選び、
長さ $n$ の数列 $(a_1,\ldots,a_{k-1},a_k,\ldots,a_n)$ を長さ $n+1$ の数列 $(a_1,\ldots,a_{k-1},1,a_k-1,\ldots,a_n)$ に変化させる。
操作 $2$ :
$1 \leq k \leq n$ を満たす整数 $k$ を選び、
長さ $n$ の数列 $(a_1,\ldots,a_k,a_{k+1},\ldots,a_n)$ を長さ $n+1$ の数列 $(a_1,\ldots,a_k-1,1,a_{k+1},\ldots,a_n)$ に変化させる。
入力形式
$N$ $M$
$A_1$ $\ldots$ $A_N$
$B_1$ $\ldots$ $B_M$
制約
$1 \leq N \leq 100{,}000$
$1 \leq M \leq 100{,}000$
$1 \leq A_i \leq 100{,}000 $ $(1 \leq i \leq N) $
$1 \leq B_j \leq 100{,}000 $ $(1 \leq j \leq M) $
入力は整数で与えられる。
出力形式
答えを $998244353$ で割ったあまりを一行に出力してください。
入力例 1
1 3
4
1 2 1
出力例 1
2
数列 $A$ は $(4)$ です。
$k=1$ として操作 $1$ を行うと、数列は
$(1,3)$ となります。さらに、$k=2$ として操作 $2$ を行うと数列は
$(1,2,1)$ となり、$B$ に一致します。
また、$k=1$ として操作 $2$ を行い、
その後 $k=1$ として操作 $1$ を行った場合も
操作後の数列は $(1,2,1)$ となり、$B$ に一致します。
$A$ を $B$ に一致させる操作の方法は以上の $2$ 通りなので、 $2$ を $998244353$ で割ったあまりである $2$ を出力してください。
入力例 2
3 1
1 2 3
100
出力例 2
0
どのように操作を行っても、数列 $A$ を数列 $B$ に一致させることができないような場合もあります。
入力例 3
1 5
5
1 1 1 1 1
出力例 3
16

Submitted solutions:

code_snippet: #include <iostream>
#include <cstdio>
#include <algorithm>

using namespace std;

const int N = 200010;
const int MOD = 998244353;

long long n, m, a[N], b[N];
long long fac[N], ifac[N];

long long qpow(long long a, long long b) {
    long long res = 1;
    while (b) {
        if (b & 1) res = res * a % MOD;
        a = a * a % MOD;
        b >>= 1;
    }
    return res;
}

void init() {
    fac[0] = 1;
    for (int i = 1; i <= 200000; i++) {
        fac[i] = fac[i - 1] * i % MOD;
    }
    ifac[200000] = qpow(fac[200000], MOD - 2);
    for (int i = 199999; i >= 0; i--) {
        ifac[i] = ifac[i + 1] * (i + 1) % MOD;
    }
}

long long C(int n, int m) {
    if (n < m) return 0;
    return fac[n] * ifac[m] % MOD * ifac[n - m] % MOD;
}

int main() {
    init();
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        scanf("%lld", &a[i]);
    }
    for (int i = 1; i <= m; i++) {
        scanf("%lld", &b[i]);
    }
    long long c = 0, ans = 1;
    int j=0;
    for (int i = 1; i <= n; i++) {
        long long sum = 0,L = 0,R = 0;
        bool mid = 0;
        while (j <= m && sum < a[i]) {
            sum+=b[++j];
            if(b[j] == 1){
                if(mid)R++;
                else L++;
            }else{
                if(mid)ans=0;
                else mid=1;
            }
        }
        if (sum == a[i]) {
            if(mid)
                ans = ans * C(L+R, R) % MOD,c += L+R,ans = ans * ifac[L+R] % MOD;
            else
                ans = ans * qpow(2, L - 1) % MOD,c += L-1,ans = ans * ifac[L-1] % MOD;
        } else {
            ans = 0;
        }
    }
    if(j != m)ans=0;
    ans = ans * fac[c] % MOD;
    cout << ans << endl;
    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 9648
final_rank: 3

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


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

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

void solve(){
	ll N,M;
	cin>>N>>M;
	vector<ll> A(N),B(M);
	for(int i=0;i<N;i++)cin>>A[i];
	for(int i=0;i<M;i++)cin>>B[i];
	ll an=1;
	ll L=0;
	vector<int> P;
	for(int i=0;i<N;i++){
		ll S=0;
		ll id=-1,pd=0,af=0;
		while(L<M&&S<A[i]){
			S+=B[L];
			if(B[L]>1){
				if(id!=-1){
					cout<<0<<endl;
					return;
				}
				id=L;
			}
			else if(id!=-1)af++;
			else pd++;
			L++;
		}
		if(S!=A[i]){
			cout<<0<<endl;
			return;
		}
		if(id==-1){
			an=(an*P2[S-1])%mod;
			P.push_back(S-1);
		}
		else{
			an=(an*nCk(af+pd,af))%mod;
			P.push_back(af+pd);
		}
	}
	if(L!=M)an=0;
	ll d=0;
	for(ll p:P){
		d+=p;
		an=(an*factinv[p])%mod;
	}
	an=(an*fact[d]);
	an%=mod;
	if(an<0)an+=mod;
	cout<<an<<endl;
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	
	// int T;
	// cin>>T;
	// while(T--)
	prenCkModp(200000);
	solve();
}
accuracy: 1
time_ms: 10
memory_kb: 11448
final_rank: 4

code_snippet: #ifndef HIDDEN_IN_VS // 折りたたみ用

// 警告の抑制
#define _CRT_SECURE_NO_WARNINGS

// ライブラリの読み込み
#include <bits/stdc++.h>
using namespace std;

// 型名の短縮
using ll = long long; using ull = unsigned long long; // -2^63 ～ 2^63 = 9e18（int は -2^31 ～ 2^31 = 2e9）
using pii = pair<int, int>;	using pll = pair<ll, ll>;	using pil = pair<int, ll>;	using pli = pair<ll, int>;
using vi = vector<int>;		using vvi = vector<vi>;		using vvvi = vector<vvi>;	using vvvvi = vector<vvvi>;
using vl = vector<ll>;		using vvl = vector<vl>;		using vvvl = vector<vvl>;	using vvvvl = vector<vvvl>;
using vb = vector<bool>;	using vvb = vector<vb>;		using vvvb = vector<vvb>;
using vc = vector<char>;	using vvc = vector<vc>;		using vvvc = vector<vvc>;
using vd = vector<double>;	using vvd = vector<vd>;		using vvvd = vector<vvd>;
template <class T> using priority_queue_rev = priority_queue<T, vector<T>, greater<T>>;
using Graph = vvi;

// 定数の定義
const double PI = acos(-1);
int DX[4] = { 1, 0, -1, 0 }; // 4 近傍（下，右，上，左）
int DY[4] = { 0, 1, 0, -1 };
int INF = 1001001001; ll INFL = 4004004003094073385LL; // (int)INFL = INF, (int)(-INFL) = -INF;

// 入出力高速化
struct fast_io { fast_io() { cin.tie(nullptr); ios::sync_with_stdio(false); cout << fixed << setprecision(18); } } fastIOtmp;

// 汎用マクロの定義
#define all(a) (a).begin(), (a).end()
#define sz(x) ((int)(x).size())
#define lbpos(a, x) (int)distance((a).begin(), std::lower_bound(all(a), (x)))
#define ubpos(a, x) (int)distance((a).begin(), std::upper_bound(all(a), (x)))
#define Yes(b) {cout << ((b) ? "Yes\n" : "No\n");}
#define rep(i, n) for(int i = 0, i##_len = int(n); i < i##_len; ++i) // 0 から n-1 まで昇順
#define repi(i, s, t) for(int i = int(s), i##_end = int(t); i <= i##_end; ++i) // s から t まで昇順
#define repir(i, s, t) for(int i = int(s), i##_end = int(t); i >= i##_end; --i) // s から t まで降順
#define repe(v, a) for(const auto& v : (a)) // a の全要素（変更不可能）
#define repea(v, a) for(auto& v : (a)) // a の全要素（変更可能）
#define repb(set, d) for(int set = 0, set##_ub = 1 << int(d); set < set##_ub; ++set) // d ビット全探索（昇順）
#define repis(i, set) for(int i = lsb(set), bset##i = set; i < 32; bset##i -= 1 << i, i = lsb(bset##i)) // set の全要素（昇順）
#define repp(a) sort(all(a)); for(bool a##_perm = true; a##_perm; a##_perm = next_permutation(all(a))) // a の順列全て（昇順）
#define uniq(a) {sort(all(a)); (a).erase(unique(all(a)), (a).end());} // 重複除去
#define EXIT(a) {cout << (a) << endl; exit(0);} // 強制終了
#define inQ(x, y, u, l, d, r) ((u) <= (x) && (l) <= (y) && (x) < (d) && (y) < (r)) // 半開矩形内判定

// 汎用関数の定義
template <class T> inline ll powi(T n, int k) { ll v = 1; rep(i, k) v *= n; return v; }
template <class T> inline bool chmax(T& M, const T& x) { if (M < x) { M = x; return true; } return false; } // 最大値を更新（更新されたら true を返す）
template <class T> inline bool chmin(T& m, const T& x) { if (m > x) { m = x; return true; } return false; } // 最小値を更新（更新されたら true を返す）
template <class T> inline T getb(T set, int i) { return (set >> i) & T(1); }
template <class T> inline T smod(T n, T m) { n %= m; if (n < 0) n += m; return n; } // 非負mod

// 演算子オーバーロード
template <class T, class U> inline istream& operator>>(istream& is, pair<T, U>& p) { is >> p.first >> p.second; return is; }
template <class T> inline istream& operator>>(istream& is, vector<T>& v) { repea(x, v) is >> x; return is; }
template <class T> inline vector<T>& operator--(vector<T>& v) { repea(x, v) --x; return v; }
template <class T> inline vector<T>& operator++(vector<T>& v) { repea(x, v) ++x; return v; }

#endif // 折りたたみ用


//#if __has_include(<atcoder/all>)
//#include <atcoder/all>
//using namespace atcoder;
//
//#ifdef _MSC_VER
//#include "localACL.hpp"
//#endif
//
//using mint = modint998244353;
////using mint = static_modint<1000000007>;
////using mint = modint; // mint::set_mod(m);
//
//namespace atcoder {
//	inline istream& operator>>(istream& is, mint& x) { ll x_; is >> x_; x = x_; return is; }
//	inline ostream& operator<<(ostream& os, const mint& x) { os << x.val(); return os; }
//}
//using vm = vector<mint>; using vvm = vector<vm>; using vvvm = vector<vvm>; using vvvvm = vector<vvvm>; using pim = pair<int, mint>;
//#endif


#ifdef _MSC_VER // 手元環境（Visual Studio）
#include "local.hpp"
#else // 提出用（gcc）
inline int popcount(int n) { return __builtin_popcount(n); }
inline int popcount(ll n) { return __builtin_popcountll(n); }
inline int lsb(int n) { return n != 0 ? __builtin_ctz(n) : 32; }
inline int lsb(ll n) { return n != 0 ? __builtin_ctzll(n) : 64; }
inline int msb(int n) { return n != 0 ? (31 - __builtin_clz(n)) : -1; }
inline int msb(ll n) { return n != 0 ? (63 - __builtin_clzll(n)) : -1; }
#define dump(...)
#define dumpel(...)
#define dump_math(v)
#define input_from_file(f)
#define output_to_file(f)
#define Assert(b) { if (!(b)) { vc MLE(1<<30); EXIT(MLE.back()); } } // RE の代わりに MLE を出す
#endif


//【有限体 F_p 上の計算（32 bit）】
template <ll MOD> struct Static_modint {
	// verify : https://www.codechef.com/problems/MUSICAL

	ll v;

	// コンストラクタ
	Static_modint() noexcept : v(0) {};
	Static_modint(const Static_modint& a) = default;
	Static_modint(int a) noexcept : v(a% MOD) { if (v < 0) v += MOD; };
	Static_modint(ll a) noexcept : v(a% MOD) { if (v < 0) v += MOD; };

	// 代入
	Static_modint& operator=(const Static_modint& a) = default;
	Static_modint& operator=(int a) { v = a % MOD; if (v < 0) v += MOD; return *this; }
	Static_modint& operator=(ll a) { v = a % MOD; if (v < 0) v += MOD; return *this; }

	// 入出力
	friend istream& operator>> (istream& is, Static_modint& x) {
		is >> x.v; x.v %= MOD; if (x.v < 0) x.v += MOD; return is;
	}
	friend ostream& operator<< (ostream& os, const Static_modint& x) { os << x.v; return os; }

	// 比較（参考 : https://twitter.com/KakurenboUni/status/1717463221190414472）
	friend bool operator==(const Static_modint& a, const Static_modint& b) { return a.v == b.v; }
	friend bool operator!=(const Static_modint& a, const Static_modint& b) { return a.v != b.v; }

	// 単項演算
	Static_modint operator-() const { Static_modint a; if (v > 0) a.v = MOD - v; return a; }
	Static_modint& operator++() { v++; if (v == MOD) v = 0; return *this; }
	Static_modint operator++(int) { Static_modint tmp = *this; ++(*this); return tmp; }
	Static_modint& operator--() { v--; if (v == -1) v = MOD - 1; return *this; }
	Static_modint operator--(int) { Static_modint tmp = *this; --(*this); return tmp; }

	// 二項演算
	Static_modint& operator+=(const Static_modint& b) { v += b.v; if (v >= MOD) v -= MOD; return *this; }
	Static_modint& operator-=(const Static_modint& b) { v -= b.v; if (v < 0) v += MOD; return *this; }
	Static_modint& operator*=(const Static_modint& b) { v = (v * b.v) % MOD; return *this; }
	Static_modint& operator/=(const Static_modint& b) { *this *= b.inv(); return *this; }
	friend Static_modint operator+(Static_modint a, const Static_modint& b) { a += b; return a; }
	friend Static_modint operator-(Static_modint a, const Static_modint& b) { a -= b; return a; }
	friend Static_modint operator*(Static_modint a, const Static_modint& b) { a *= b; return a; }
	friend Static_modint operator/(Static_modint a, const Static_modint& b) { a /= b; return a; }

	// 累乗（0^0 := 1）
	Static_modint pow(ll d) const {
		Static_modint res(1), pow2 = *this;
		while (d > 0) {
			if (d & 1) res *= pow2;
			pow2 *= pow2;
			d >>= 1;
		}
		return res;
	}

	// 逆元（0^(-1) は未定義）
	Static_modint inv() const { Assert(v != 0); return pow(MOD - 2); }

	// 法の確認
	static int mod() { return int(MOD); }

	// 値の確認
	int val() const { return int(v); }
};
//using mint = Static_modint<1000000007>;
using mint = Static_modint<998244353>;
using vm = vector<mint>; using vvm = vector<vm>; using vvvm = vector<vvm>; using vvvvm = vector<vvvm>; using pim = pair<int, mint>;


//【階乗など（法が大きな素数）】
/*
* Factorial_mint(int N) : O(n)
*	N まで計算可能として初期化する．
*
* mint fact(int n) : O(1)
*	n! を返す．
*
* mint fact_inv(int n) : O(1)
*	1/n! を返す（n が負なら 0 を返す）
*
* mint inv(int n) : O(1)
*	1/n を返す．
*
* mint perm(int n, int r) : O(1)
*	順列の数 nPr を返す．
*
* mint bin(int n, int r) : O(1)
*	二項係数 nCr を返す．
*
* mint bin_inv(int n, int r) : O(1)
*	二項係数の逆数 1/nCr を返す．
*
* mint mul(vi rs) : O(|rs|)
*	多項係数 nC[rs] を返す．（n = Σrs）
*
* mint hom(int n, int r) : O(1)
*	重複組合せの数 nHr = n+r-1Cr を返す（0H0 = 1 とする）
*
* mint neg_bin(int n, int r) : O(1)
*	負の二項係数 nCr = (-1)^r -n+r-1Cr を返す（n ≦ 0, r ≧ 0）
*
* mint pochhammer(int x, int n) : O(1)
*	ポッホハマー記号 x^(n) を返す（n ≧ 0）
*
* mint pochhammer_inv(int x, int n) : O(1)
*	ポッホハマー記号の逆数 1/x^(n) を返す（n ≧ 0）
*/
class Factorial_mint {
	int n_max;

	// 階乗と階乗の逆数の値を保持するテーブル
	vm fac, fac_inv;

public:
	// n! までの階乗とその逆数を前計算しておく．O(n)
	Factorial_mint(int n) : n_max(n), fac(n + 1), fac_inv(n + 1) {
		// verify : https://atcoder.jp/contests/dwacon6th-prelims/tasks/dwacon6th_prelims_b

		fac[0] = 1;
		repi(i, 1, n) fac[i] = fac[i - 1] * i;

		fac_inv[n] = fac[n].inv();
		repir(i, n - 1, 0) fac_inv[i] = fac_inv[i + 1] * (i + 1);
	}
	Factorial_mint() : n_max(0) {} // ダミー

	// n! を返す．
	mint fact(int n) const {
		// verify : https://atcoder.jp/contests/dwacon6th-prelims/tasks/dwacon6th_prelims_b

		Assert(0 <= n && n <= n_max);
		return fac[n];
	}

	// 1/n! を返す（n が負なら 0 を返す）
	mint fact_inv(int n) const {
		// verify : https://atcoder.jp/contests/abc289/tasks/abc289_h

		Assert(n <= n_max);
		if (n < 0) return 0;
		return fac_inv[n];
	}

	// 1/n を返す．
	mint inv(int n) const {
		// verify : https://atcoder.jp/contests/exawizards2019/tasks/exawizards2019_d

		Assert(n > 0);
		Assert(n <= n_max);
		return fac[n - 1] * fac_inv[n];
	}

	// 順列の数 nPr を返す．
	mint perm(int n, int r) const {
		// verify : https://atcoder.jp/contests/abc172/tasks/abc172_e

		Assert(n <= n_max);

		if (r < 0 || n - r < 0) return 0;
		return fac[n] * fac_inv[n - r];
	}

	// 二項係数 nCr を返す．
	mint bin(int n, int r) const {
		// verify : https://judge.yosupo.jp/problem/binomial_coefficient_prime_mod

		Assert(n <= n_max);
		if (r < 0 || n - r < 0) return 0;
		return fac[n] * fac_inv[r] * fac_inv[n - r];
	}

	// 二項係数の逆数 1/nCr を返す．
	mint bin_inv(int n, int r) const {
		// verify : https://www.codechef.com/problems/RANDCOLORING

		Assert(n <= n_max);
		Assert(r >= 0);
		Assert(n - r >= 0);
		return fac_inv[n] * fac[r] * fac[n - r];
	}

	// 多項係数 nC[rs] を返す．
	mint mul(const vi& rs) const {
		// verify : https://yukicoder.me/problems/no/2141

		if (*min_element(all(rs)) < 0) return 0;
		int n = accumulate(all(rs), 0);
		Assert(n <= n_max);

		mint res = fac[n];
		repe(r, rs) res *= fac_inv[r];

		return res;
	}

	// 重複組合せの数 nHr = n+r-1Cr を返す（0H0 = 1 とする）
	mint hom(int n, int r) {
		// verify : https://mojacoder.app/users/riantkb/problems/toj_ex_2

		if (n == 0) return (int)(r == 0);
		Assert(n + r - 1 <= n_max);
		if (r < 0 || n - 1 < 0) return 0;
		return fac[n + r - 1] * fac_inv[r] * fac_inv[n - 1];
	}

	// 負の二項係数 nCr を返す（n ≦ 0, r ≧ 0）
	mint neg_bin(int n, int r) {
		// verify : https://atcoder.jp/contests/abc345/tasks/abc345_g

		if (n == 0) return (int)(r == 0);
		Assert(-n + r - 1 <= n_max);
		if (r < 0 || -n - 1 < 0) return 0;
		return (r & 1 ? -1 : 1) * fac[-n + r - 1] * fac_inv[r] * fac_inv[-n - 1];
	}

	// ポッホハマー記号 x^(n) を返す（n ≧ 0）
	mint pochhammer(int x, int n) {
		// verify : https://atcoder.jp/contests/agc070/tasks/agc070_c

		int x2 = x + n - 1;
		if (x <= 0 && 0 <= x2) return 0;

		if (x > 0) {
			Assert(x2 <= n_max);
			return fac[x2] * fac_inv[x - 1];
		}
		else {
			Assert(-x <= n_max);
			return (n & 1 ? -1 : 1) * fac[-x] * fac_inv[-x2 - 1];
		}
	}

	// ポッホハマー記号の逆数 1/x^(n) を返す（n ≧ 0）
	mint pochhammer_inv(int x, int n) {
		// verify : https://atcoder.jp/contests/agc070/tasks/agc070_c

		int x2 = x + n - 1;
		Assert(!(x <= 0 && 0 <= x2));

		if (x > 0) {
			Assert(x2 <= n_max);
			return fac_inv[x2] * fac[x - 1];
		}
		else {
			Assert(-x <= n_max);
			return (n & 1 ? -1 : 1) * fac_inv[-x] * fac[-x2 - 1];
		}
	}
};


int main() {
	input_from_file("input.txt");
//	output_to_file("output.txt");

	int n, m;
	cin >> n >> m;

	vl a(n), b(m);
	cin >> a >> b;

	Factorial_mint fm(m);

	vm pow2(m + 1);
	pow2[0] = 1;
	repi(j, 1, m) pow2[j] = pow2[j - 1] * 2;

	mint res = 1; vi lrs;

	int j = 0;

	rep(i, n) {
		ll s = 0; int l = 0, c = 0, r = 0;

		while (s < a[i]) {
			if (j == m) EXIT(0);

			s += b[j];

			if (b[j] == 1) {
				if (c == 0) l++;
				else r++;
			}
			else {
				if (c == 0) c++;
				else EXIT(0);
			}

			j++;
		}

		if (s != a[i]) EXIT(0);

		if (c == 0) {
			res *= pow2[l - 1];
			lrs.push_back(l - 1);
		}
		else {
			lrs.push_back(l);
			lrs.push_back(r);
		}
	}

	if (j != m) EXIT(0);

	res *= fm.mul(lrs);

	EXIT(res);
}
accuracy: 1
time_ms: 10
memory_kb: 8004
final_rank: 1

code_snippet: #ifndef HIDDEN_IN_VS // 折りたたみ用

// 警告の抑制
#define _CRT_SECURE_NO_WARNINGS

// ライブラリの読み込み
#include <bits/stdc++.h>
using namespace std;

// 型名の短縮
using ll = long long; using ull = unsigned long long; // -2^63 ～ 2^63 = 9e18（int は -2^31 ～ 2^31 = 2e9）
using pii = pair<int, int>;	using pll = pair<ll, ll>;	using pil = pair<int, ll>;	using pli = pair<ll, int>;
using vi = vector<int>;		using vvi = vector<vi>;		using vvvi = vector<vvi>;	using vvvvi = vector<vvvi>;
using vl = vector<ll>;		using vvl = vector<vl>;		using vvvl = vector<vvl>;	using vvvvl = vector<vvvl>;
using vb = vector<bool>;	using vvb = vector<vb>;		using vvvb = vector<vvb>;
using vc = vector<char>;	using vvc = vector<vc>;		using vvvc = vector<vvc>;
using vd = vector<double>;	using vvd = vector<vd>;		using vvvd = vector<vvd>;
template <class T> using priority_queue_rev = priority_queue<T, vector<T>, greater<T>>;
using Graph = vvi;

// 定数の定義
const double PI = acos(-1);
int DX[4] = { 1, 0, -1, 0 }; // 4 近傍（下，右，上，左）
int DY[4] = { 0, 1, 0, -1 };
int INF = 1001001001; ll INFL = 4004004003094073385LL; // (int)INFL = INF, (int)(-INFL) = -INF;

// 入出力高速化
struct fast_io { fast_io() { cin.tie(nullptr); ios::sync_with_stdio(false); cout << fixed << setprecision(18); } } fastIOtmp;

// 汎用マクロの定義
#define all(a) (a).begin(), (a).end()
#define sz(x) ((int)(x).size())
#define lbpos(a, x) (int)distance((a).begin(), std::lower_bound(all(a), (x)))
#define ubpos(a, x) (int)distance((a).begin(), std::upper_bound(all(a), (x)))
#define Yes(b) {cout << ((b) ? "Yes\n" : "No\n");}
#define rep(i, n) for(int i = 0, i##_len = int(n); i < i##_len; ++i) // 0 から n-1 まで昇順
#define repi(i, s, t) for(int i = int(s), i##_end = int(t); i <= i##_end; ++i) // s から t まで昇順
#define repir(i, s, t) for(int i = int(s), i##_end = int(t); i >= i##_end; --i) // s から t まで降順
#define repe(v, a) for(const auto& v : (a)) // a の全要素（変更不可能）
#define repea(v, a) for(auto& v : (a)) // a の全要素（変更可能）
#define repb(set, d) for(int set = 0, set##_ub = 1 << int(d); set < set##_ub; ++set) // d ビット全探索（昇順）
#define repis(i, set) for(int i = lsb(set), bset##i = set; i < 32; bset##i -= 1 << i, i = lsb(bset##i)) // set の全要素（昇順）
#define repp(a) sort(all(a)); for(bool a##_perm = true; a##_perm; a##_perm = next_permutation(all(a))) // a の順列全て（昇順）
#define uniq(a) {sort(all(a)); (a).erase(unique(all(a)), (a).end());} // 重複除去
#define EXIT(a) {cout << (a) << endl; exit(0);} // 強制終了
#define inQ(x, y, u, l, d, r) ((u) <= (x) && (l) <= (y) && (x) < (d) && (y) < (r)) // 半開矩形内判定

// 汎用関数の定義
template <class T> inline ll powi(T n, int k) { ll v = 1; rep(i, k) v *= n; return v; }
template <class T> inline bool chmax(T& M, const T& x) { if (M < x) { M = x; return true; } return false; } // 最大値を更新（更新されたら true を返す）
template <class T> inline bool chmin(T& m, const T& x) { if (m > x) { m = x; return true; } return false; } // 最小値を更新（更新されたら true を返す）
template <class T> inline T getb(T set, int i) { return (set >> i) & T(1); }
template <class T> inline T smod(T n, T m) { n %= m; if (n < 0) n += m; return n; } // 非負mod

// 演算子オーバーロード
template <class T, class U> inline istream& operator>>(istream& is, pair<T, U>& p) { is >> p.first >> p.second; return is; }
template <class T> inline istream& operator>>(istream& is, vector<T>& v) { repea(x, v) is >> x; return is; }
template <class T> inline vector<T>& operator--(vector<T>& v) { repea(x, v) --x; return v; }
template <class T> inline vector<T>& operator++(vector<T>& v) { repea(x, v) ++x; return v; }

#endif // 折りたたみ用


//#if __has_include(<atcoder/all>)
//#include <atcoder/all>
//using namespace atcoder;
//
//#ifdef _MSC_VER
//#include "localACL.hpp"
//#endif
//
//using mint = modint998244353;
////using mint = static_modint<1000000007>;
////using mint = modint; // mint::set_mod(m);
//
//namespace atcoder {
//	inline istream& operator>>(istream& is, mint& x) { ll x_; is >> x_; x = x_; return is; }
//	inline ostream& operator<<(ostream& os, const mint& x) { os << x.val(); return os; }
//}
//using vm = vector<mint>; using vvm = vector<vm>; using vvvm = vector<vvm>; using vvvvm = vector<vvvm>; using pim = pair<int, mint>;
//#endif


#ifdef _MSC_VER // 手元環境（Visual Studio）
#include "local.hpp"
#else // 提出用（gcc）
inline int popcount(int n) { return __builtin_popcount(n); }
inline int popcount(ll n) { return __builtin_popcountll(n); }
inline int lsb(int n) { return n != 0 ? __builtin_ctz(n) : 32; }
inline int lsb(ll n) { return n != 0 ? __builtin_ctzll(n) : 64; }
inline int msb(int n) { return n != 0 ? (31 - __builtin_clz(n)) : -1; }
inline int msb(ll n) { return n != 0 ? (63 - __builtin_clzll(n)) : -1; }
#define dump(...)
#define dumpel(...)
#define dump_math(v)
#define input_from_file(f)
#define output_to_file(f)
#define Assert(b) { if (!(b)) { vc MLE(1<<30); EXIT(MLE.back()); } } // RE の代わりに MLE を出す
#endif


//【有限体 F_p 上の計算（32 bit）】
template <ll MOD> struct Static_modint {
	// verify : https://www.codechef.com/problems/MUSICAL

	ll v;

	// コンストラクタ
	Static_modint() noexcept : v(0) {};
	Static_modint(const Static_modint& a) = default;
	Static_modint(int a) noexcept : v(a% MOD) { if (v < 0) v += MOD; };
	Static_modint(ll a) noexcept : v(a% MOD) { if (v < 0) v += MOD; };

	// 代入
	Static_modint& operator=(const Static_modint& a) = default;
	Static_modint& operator=(int a) { v = a % MOD; if (v < 0) v += MOD; return *this; }
	Static_modint& operator=(ll a) { v = a % MOD; if (v < 0) v += MOD; return *this; }

	// 入出力
	friend istream& operator>> (istream& is, Static_modint& x) {
		is >> x.v; x.v %= MOD; if (x.v < 0) x.v += MOD; return is;
	}
	friend ostream& operator<< (ostream& os, const Static_modint& x) { os << x.v; return os; }

	// 比較（参考 : https://twitter.com/KakurenboUni/status/1717463221190414472）
	friend bool operator==(const Static_modint& a, const Static_modint& b) { return a.v == b.v; }
	friend bool operator!=(const Static_modint& a, const Static_modint& b) { return a.v != b.v; }

	// 単項演算
	Static_modint operator-() const { Static_modint a; if (v > 0) a.v = MOD - v; return a; }
	Static_modint& operator++() { v++; if (v == MOD) v = 0; return *this; }
	Static_modint operator++(int) { Static_modint tmp = *this; ++(*this); return tmp; }
	Static_modint& operator--() { v--; if (v == -1) v = MOD - 1; return *this; }
	Static_modint operator--(int) { Static_modint tmp = *this; --(*this); return tmp; }

	// 二項演算
	Static_modint& operator+=(const Static_modint& b) { v += b.v; if (v >= MOD) v -= MOD; return *this; }
	Static_modint& operator-=(const Static_modint& b) { v -= b.v; if (v < 0) v += MOD; return *this; }
	Static_modint& operator*=(const Static_modint& b) { v = (v * b.v) % MOD; return *this; }
	Static_modint& operator/=(const Static_modint& b) { *this *= b.inv(); return *this; }
	friend Static_modint operator+(Static_modint a, const Static_modint& b) { a += b; return a; }
	friend Static_modint operator-(Static_modint a, const Static_modint& b) { a -= b; return a; }
	friend Static_modint operator*(Static_modint a, const Static_modint& b) { a *= b; return a; }
	friend Static_modint operator/(Static_modint a, const Static_modint& b) { a /= b; return a; }

	// 累乗（0^0 := 1）
	Static_modint pow(ll d) const {
		Static_modint res(1), pow2 = *this;
		while (d > 0) {
			if (d & 1) res *= pow2;
			pow2 *= pow2;
			d >>= 1;
		}
		return res;
	}

	// 逆元（0^(-1) は未定義）
	Static_modint inv() const { Assert(v != 0); return pow(MOD - 2); }

	// 法の確認
	static int mod() { return int(MOD); }

	// 値の確認
	int val() const { return int(v); }
};
//using mint = Static_modint<1000000007>;
using mint = Static_modint<998244353>;
using vm = vector<mint>; using vvm = vector<vm>; using vvvm = vector<vvm>; using vvvvm = vector<vvvm>; using pim = pair<int, mint>;


//【階乗など（法が大きな素数）】
/*
* Factorial_mint(int N) : O(n)
*	N まで計算可能として初期化する．
*
* mint fact(int n) : O(1)
*	n! を返す．
*
* mint fact_inv(int n) : O(1)
*	1/n! を返す（n が負なら 0 を返す）
*
* mint inv(int n) : O(1)
*	1/n を返す．
*
* mint perm(int n, int r) : O(1)
*	順列の数 nPr を返す．
*
* mint bin(int n, int r) : O(1)
*	二項係数 nCr を返す．
*
* mint bin_inv(int n, int r) : O(1)
*	二項係数の逆数 1/nCr を返す．
*
* mint mul(vi rs) : O(|rs|)
*	多項係数 nC[rs] を返す．（n = Σrs）
*
* mint hom(int n, int r) : O(1)
*	重複組合せの数 nHr = n+r-1Cr を返す（0H0 = 1 とする）
*
* mint neg_bin(int n, int r) : O(1)
*	負の二項係数 nCr = (-1)^r -n+r-1Cr を返す（n ≦ 0, r ≧ 0）
*
* mint pochhammer(int x, int n) : O(1)
*	ポッホハマー記号 x^(n) を返す（n ≧ 0）
*
* mint pochhammer_inv(int x, int n) : O(1)
*	ポッホハマー記号の逆数 1/x^(n) を返す（n ≧ 0）
*/
class Factorial_mint {
	int n_max;

	// 階乗と階乗の逆数の値を保持するテーブル
	vm fac, fac_inv;

public:
	// n! までの階乗とその逆数を前計算しておく．O(n)
	Factorial_mint(int n) : n_max(n), fac(n + 1), fac_inv(n + 1) {
		// verify : https://atcoder.jp/contests/dwacon6th-prelims/tasks/dwacon6th_prelims_b

		fac[0] = 1;
		repi(i, 1, n) fac[i] = fac[i - 1] * i;

		fac_inv[n] = fac[n].inv();
		repir(i, n - 1, 0) fac_inv[i] = fac_inv[i + 1] * (i + 1);
	}
	Factorial_mint() : n_max(0) {} // ダミー

	// n! を返す．
	mint fact(int n) const {
		// verify : https://atcoder.jp/contests/dwacon6th-prelims/tasks/dwacon6th_prelims_b

		Assert(0 <= n && n <= n_max);
		return fac[n];
	}

	// 1/n! を返す（n が負なら 0 を返す）
	mint fact_inv(int n) const {
		// verify : https://atcoder.jp/contests/abc289/tasks/abc289_h

		Assert(n <= n_max);
		if (n < 0) return 0;
		return fac_inv[n];
	}

	// 1/n を返す．
	mint inv(int n) const {
		// verify : https://atcoder.jp/contests/exawizards2019/tasks/exawizards2019_d

		Assert(n > 0);
		Assert(n <= n_max);
		return fac[n - 1] * fac_inv[n];
	}

	// 順列の数 nPr を返す．
	mint perm(int n, int r) const {
		// verify : https://atcoder.jp/contests/abc172/tasks/abc172_e

		Assert(n <= n_max);

		if (r < 0 || n - r < 0) return 0;
		return fac[n] * fac_inv[n - r];
	}

	// 二項係数 nCr を返す．
	mint bin(int n, int r) const {
		// verify : https://judge.yosupo.jp/problem/binomial_coefficient_prime_mod

		Assert(n <= n_max);
		if (r < 0 || n - r < 0) return 0;
		return fac[n] * fac_inv[r] * fac_inv[n - r];
	}

	// 二項係数の逆数 1/nCr を返す．
	mint bin_inv(int n, int r) const {
		// verify : https://www.codechef.com/problems/RANDCOLORING

		Assert(n <= n_max);
		Assert(r >= 0);
		Assert(n - r >= 0);
		return fac_inv[n] * fac[r] * fac[n - r];
	}

	// 多項係数 nC[rs] を返す．
	mint mul(const vi& rs) const {
		// verify : https://yukicoder.me/problems/no/2141

		if (*min_element(all(rs)) < 0) return 0;
		int n = accumulate(all(rs), 0);
		Assert(n <= n_max);

		mint res = fac[n];
		repe(r, rs) res *= fac_inv[r];

		return res;
	}

	// 重複組合せの数 nHr = n+r-1Cr を返す（0H0 = 1 とする）
	mint hom(int n, int r) {
		// verify : https://mojacoder.app/users/riantkb/problems/toj_ex_2

		if (n == 0) return (int)(r == 0);
		Assert(n + r - 1 <= n_max);
		if (r < 0 || n - 1 < 0) return 0;
		return fac[n + r - 1] * fac_inv[r] * fac_inv[n - 1];
	}

	// 負の二項係数 nCr を返す（n ≦ 0, r ≧ 0）
	mint neg_bin(int n, int r) {
		// verify : https://atcoder.jp/contests/abc345/tasks/abc345_g

		if (n == 0) return (int)(r == 0);
		Assert(-n + r - 1 <= n_max);
		if (r < 0 || -n - 1 < 0) return 0;
		return (r & 1 ? -1 : 1) * fac[-n + r - 1] * fac_inv[r] * fac_inv[-n - 1];
	}

	// ポッホハマー記号 x^(n) を返す（n ≧ 0）
	mint pochhammer(int x, int n) {
		// verify : https://atcoder.jp/contests/agc070/tasks/agc070_c

		int x2 = x + n - 1;
		if (x <= 0 && 0 <= x2) return 0;

		if (x > 0) {
			Assert(x2 <= n_max);
			return fac[x2] * fac_inv[x - 1];
		}
		else {
			Assert(-x <= n_max);
			return (n & 1 ? -1 : 1) * fac[-x] * fac_inv[-x2 - 1];
		}
	}

	// ポッホハマー記号の逆数 1/x^(n) を返す（n ≧ 0）
	mint pochhammer_inv(int x, int n) {
		// verify : https://atcoder.jp/contests/agc070/tasks/agc070_c

		int x2 = x + n - 1;
		Assert(!(x <= 0 && 0 <= x2));

		if (x > 0) {
			Assert(x2 <= n_max);
			return fac_inv[x2] * fac[x - 1];
		}
		else {
			Assert(-x <= n_max);
			return (n & 1 ? -1 : 1) * fac_inv[-x] * fac[-x2 - 1];
		}
	}
};


int main() {
//	input_from_file("input.txt");
//	output_to_file("output.txt");

	int n, m;
	cin >> n >> m;

	vl a(n), b(m);
	cin >> a >> b;

	Factorial_mint fm(m);

	vm pow2(m + 1);
	pow2[0] = 1;
	repi(j, 1, m) pow2[j] = pow2[j - 1] * 2;

	mint res = 1; vi lrs;

	int j = 0;

	rep(i, n) {
		ll s = 0; int l = 0, c = 0, r = 0;

		while (s < a[i]) {
			if (j == m) EXIT(0);

			s += b[j];

			if (b[j] == 1) {
				if (c == 0) l++;
				else r++;
			}
			else {
				if (c == 0) c++;
				else EXIT(0);
			}

			j++;
		}

		if (s != a[i]) EXIT(0);

		if (c == 0) {
			res *= pow2[l - 1];
			lrs.push_back(l - 1);
		}
		else {
			lrs.push_back(l);
			lrs.push_back(r);
		}
	}

	res *= fm.mul(lrs);

	EXIT(res);
}
accuracy: 0.9318181818181818
time_ms: 10
memory_kb: 7880
final_rank: 13

code_snippet: #pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;

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

template <int mod> struct static_modint {
    using mint = static_modint;
    int x;

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

    mint &operator+=(const mint &rhs) {
        if ((x += rhs.x) >= mod) x -= mod;
        return *this;
    }
    mint &operator-=(const mint &rhs) {
        if ((x += mod - rhs.x) >= mod) x -= mod;
        return *this;
    }
    mint &operator*=(const mint &rhs) {
        x = (int)(1LL * x * rhs.x % mod);
        return *this;
    }
    mint &operator/=(const mint &rhs) { return *this = *this * rhs.inv(); }

    mint pow(long long n) const {
        mint _x = *this, r = 1;
        while (n) {
            if (n & 1) r *= _x;
            _x *= _x;
            n >>= 1;
        }
        return r;
    }
    mint inv() const { return pow(mod - 2); }

    mint operator+() const { return *this; }
    mint operator-() const { return mint() - *this; }
    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.x == rhs.x; }
    friend bool operator!=(const mint &lhs, const mint &rhs) { return lhs.x != rhs.x; }

    friend ostream &operator<<(ostream &os, const mint &p) { return os << p.x; }
    friend istream &operator>>(istream &is, mint &a) {
        int64_t t;
        is >> t;
        a = static_modint<mod>(t);
        return (is);
    }
};

const unsigned int mod = 998244353;
using modint = static_modint<mod>;
modint mod_pow(ll n, ll x) { return modint(n).pow(x); }
modint mod_pow(modint n, ll x) { return n.pow(x); }

template <typename T> struct Comination {
    vector<T> p, invp;

    Comination(int sz) : p(sz + 1), invp(sz + 1) {
        p[0] = 1;
        for (int i = 1; i <= sz; ++i) {
            p[i] = p[i - 1] * i;
        }
        invp[sz] = p[sz].inv();
        for (int i = sz - 1; i >= 0; --i) {
            invp[i] = invp[i + 1] * (i + 1);
        }
    }

    T comb(int n, int r) {
        if (r < 0 or n < r) return 0;
        return p[n] * invp[n - r] * invp[r];
    }
    T big_comb(T n, int r) {
        T res = invp[r];
        for (int i = 0; i < r; ++i) {
            res *= (n - i);
        }
        return res;
    }
};
using Comb = Comination<modint>;
Comb comb(1 << 20);

int main() {
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    int n, m;
    cin >> n >> m;
    vector<int> a(n), b(m);
    for (int i = 0; i < n; ++i) {
        cin >> a[i];
    }
    for (int i = 0; i < m; ++i) {
        cin >> b[i];
    }
    if (n > m) {
        cout << 0 << endl;
    } else if (n == m) {
        cout << (a == b) << endl;
    } else {
        int j = 0, rem = m - n;
        modint res = 1;
        for (int i = 0; i < m; ++i) {
            if (a[j] == b[i]) {
                j += 1;
            } else if (a[j] < b[i]) {
                cout << 0 << endl;
                return 0;
            } else {
                int k = i, cnt = 0;
                while (k < m and b[k] == 1 and cnt < a[j]) {
                    k += 1, cnt += 1;
                }
                if (cnt == 0) {
                    int dif = a[j] - b[i];
                    k += 1;
                    while (k < m and b[k] == 1 and cnt < dif) {
                        k += 1, cnt += 1;
                    }
                    if (cnt == dif) {
                        res *= comb.comb(rem, dif);
                        rem -= dif;
                        i = k - 1;
                        j += 1;
                    } else {
                        cout << 0 << endl;
                        return 0;
                    }
                } else if (cnt == a[j]) {
                    res *= comb.comb(rem, cnt - 1);
                    res *= mod_pow(2, cnt - 1);
                    rem -= (cnt - 1);
                    i = k - 1;
                    j += 1;
                } else {
                    res *= comb.comb(rem, cnt);
                    rem -= cnt;
                    i = k - 1;
                    a[j] -= cnt;
                }
            }
        }
        cout << res << endl;
    }
}
accuracy: 1
time_ms: 10
memory_kb: 11976
final_rank: 5

code_snippet: /* -*- coding: utf-8 -*-
 *
 * 3240.cc: Separate Number
 */

#include<cstdio>
#include<algorithm>
 
using namespace std;

/* constant */

const int MAX_N = 100000;
const int MOD = 998244353;

/* typedef */

typedef long long ll;

template<const int MOD>
struct MI {
  int v;
  MI(): v() {}
  MI(int _v): v(_v % MOD) {}
  MI(long long _v): v(_v % MOD) {}

  MI operator+(const MI m) const { return MI(v + m.v); }
  MI operator-(const MI m) const { return MI(v + MOD - m.v); }
  MI operator*(const MI m) const { return MI((long long)v * m.v); }

  MI &operator+=(const MI m) { return (*this = *this + m); }
  MI &operator-=(const MI m) { return (*this = *this - m); }
  MI &operator*=(const MI m) { return (*this = *this * m); }

  bool operator==(const MI m) const { return v == m.v; }
  bool operator!=(const MI m) const { return v != m.v; }

  MI pow(int n) const {  // a^n % MOD
    MI pm = 1, a = *this;
    while (n > 0) {
      if (n & 1) pm *= a;
      a *= a;
      n >>= 1;
    }
    return pm;
  }

  MI inv() const { return pow(MOD - 2); }
  MI operator/(const MI m) const { return *this * m.inv(); }
  MI &operator/=(const MI m) { return (*this = *this / m); }
};

typedef MI<MOD> mi;

/* global variables */

mi fs[MAX_N + 1], invfs[MAX_N + 1];
int as[MAX_N], bs[MAX_N];

/* subroutines */

inline mi nck(int n, int k) {  // nCk % MOD
  if (n < k || k < 0) return 0;
  return fs[n] * invfs[n - k] * invfs[k];
}

void prepare_fracs(int n) {
  fs[0] = invfs[0] = 1;
  for (int i = 1; i <= n; i++) {
    fs[i] = fs[i - 1] * i;
    invfs[i] = fs[i].inv();
  }
}

/* main */

int main() {
  prepare_fracs(MAX_N);
  
  int n, m;
  scanf("%d%d", &n, &m);
  for (int i = 0; i < n; i++) scanf("%d", as + i);
  for (int i = 0; i < m; i++) scanf("%d", bs + i);

  if (n > m) { puts("0"); return 0; }

  mi p = 1;
  int j = 0, l = 0;

  for (int i = 0; i < n; i++) {
    ll s = 0;
    int j0 = j;
    while (j < m && as[i] > s) s += bs[j++];
    if (as[i] != s) { puts("0"); return 0; }

    if (j - j0 > 1) {
      if (j - j0 == as[i]) { // all 1
	int lj = j - j0 - 1;
	p *= invfs[lj] * mi(2).pow(lj);
	l += lj;
      }
      else {
	int k0 = j0, k1 = j;
	while (k0 < j && bs[k0] == 1) k0++;
	while (k1 > j0 && bs[k1 - 1] == 1) k1--;
	if (k1 - k0 > 1) { puts("0"); return 0; }
	int l0 = k0 - j0, l1 = j - k1;
	p *= invfs[l0 + l1] * nck(l0 + l1, l0);
	l += l0 + l1;
      }
    }
  }
  if (j != m) { puts("0"); return 0; }

  p *= fs[l];

  printf("%d\n", p.v);

  return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 4340
final_rank: 2

code_snippet: /* -*- coding: utf-8 -*-
 *
 * 3240.cc: Separate Number
 */

#include<cstdio>
#include<algorithm>
 
using namespace std;

/* constant */

const int MAX_N = 100000;
const int MOD = 998244353;

/* typedef */

typedef long long ll;

template<const int MOD>
struct MI {
  int v;
  MI(): v() {}
  MI(int _v): v(_v % MOD) {}
  MI(long long _v): v(_v % MOD) {}

  MI operator+(const MI m) const { return MI(v + m.v); }
  MI operator-(const MI m) const { return MI(v + MOD - m.v); }
  MI operator*(const MI m) const { return MI((long long)v * m.v); }

  MI &operator+=(const MI m) { return (*this = *this + m); }
  MI &operator-=(const MI m) { return (*this = *this - m); }
  MI &operator*=(const MI m) { return (*this = *this * m); }

  bool operator==(const MI m) const { return v == m.v; }
  bool operator!=(const MI m) const { return v != m.v; }

  MI pow(int n) const {  // a^n % MOD
    MI pm = 1, a = *this;
    while (n > 0) {
      if (n & 1) pm *= a;
      a *= a;
      n >>= 1;
    }
    return pm;
  }

  MI inv() const { return pow(MOD - 2); }
  MI operator/(const MI m) const { return *this * m.inv(); }
  MI &operator/=(const MI m) { return (*this = *this / m); }
};

typedef MI<MOD> mi;

/* global variables */

mi fs[MAX_N + 1], invfs[MAX_N + 1];
int as[MAX_N], bs[MAX_N];

/* subroutines */

inline mi nck(int n, int k) {  // nCk % MOD
  if (n < k || k < 0) return 0;
  return fs[n] * invfs[n - k] * invfs[k];
}

void prepare_fracs(int n) {
  fs[0] = invfs[0] = 1;
  for (int i = 1; i <= n; i++) {
    fs[i] = fs[i - 1] * i;
    invfs[i] = fs[i].inv();
  }
}

/* main */

int main() {
  prepare_fracs(MAX_N);
  
  int n, m;
  scanf("%d%d", &n, &m);
  for (int i = 0; i < n; i++) scanf("%d", as + i);
  for (int i = 0; i < m; i++) scanf("%d", bs + i);

  if (n > m) { puts("0"); return 0; }

  mi p = 1;
  int l = 0;

  for (int i = 0, j = 0; i < n; i++) {
    ll s = 0;
    int j0 = j;
    while (j < m && as[i] > s) s += bs[j++];
    if (as[i] != s) { puts("0"); return 0; }

    if (j - j0 > 1) {
      if (j - j0 == as[i]) { // all 1
	int lj = j - j0 - 1;
	p *= invfs[lj] * mi(2).pow(lj);
	l += lj;
      }
      else {
	int k0 = j0, k1 = j;
	while (k0 < j && bs[k0] == 1) k0++;
	while (k1 > j0 && bs[k1 - 1] == 1) k1--;
	if (k1 - k0 > 1) { puts("0"); return 0; }
	int l0 = k0 - j0, l1 = j - k1;
	p *= invfs[l0 + l1] * nck(l0 + l1, l0);
	l += l0 + l1;
      }
    }
  }

  p *= fs[l];

  printf("%d\n", p.v);

  return 0;
}
accuracy: 0.9318181818181818
time_ms: 20
memory_kb: 4416
final_rank: 14

code_snippet: /* -*- coding: utf-8 -*-
 *
 * 3240.cc: Separate Number
 */

#include<cstdio>
#include<algorithm>
 
using namespace std;

/* constant */

const int MAX_N = 100000;
const int MOD = 998244353;

/* typedef */

typedef long long ll;

template<const int MOD>
struct MI {
  int v;
  MI(): v() {}
  MI(int _v): v(_v % MOD) {}
  MI(long long _v): v(_v % MOD) {}

  MI operator+(const MI m) const { return MI(v + m.v); }
  MI operator-(const MI m) const { return MI(v + MOD - m.v); }
  MI operator*(const MI m) const { return MI((long long)v * m.v); }

  MI &operator+=(const MI m) { return (*this = *this + m); }
  MI &operator-=(const MI m) { return (*this = *this - m); }
  MI &operator*=(const MI m) { return (*this = *this * m); }

  bool operator==(const MI m) const { return v == m.v; }
  bool operator!=(const MI m) const { return v != m.v; }

  MI pow(int n) const {  // a^n % MOD
    MI pm = 1, a = *this;
    while (n > 0) {
      if (n & 1) pm *= a;
      a *= a;
      n >>= 1;
    }
    return pm;
  }

  MI inv() const { return pow(MOD - 2); }
  MI operator/(const MI m) const { return *this * m.inv(); }
  MI &operator/=(const MI m) { return (*this = *this / m); }
};

typedef MI<MOD> mi;

/* global variables */

mi fs[MAX_N + 1], invfs[MAX_N + 1];
int as[MAX_N], bs[MAX_N];

/* subroutines */

inline mi nck(int n, int k) {  // nCk % MOD
  if (n < k || k < 0) return 0;
  return fs[n] * invfs[n - k] * invfs[k];
}

void prepare_fracs(int n) {
  fs[0] = invfs[0] = 1;
  for (int i = 1; i <= n; i++) {
    fs[i] = fs[i - 1] * i;
    invfs[i] = fs[i].inv();
  }
}

/* main */

int main() {
  prepare_fracs(MAX_N);
  
  int n, m;
  scanf("%d%d", &n, &m);
  for (int i = 0; i < n; i++) scanf("%d", as + i);
  for (int i = 0; i < m; i++) scanf("%d", bs + i);

  if (n > m) { puts("0"); return 0; }

  mi p = 1;
  int l = 0;

  for (int i = 0, j = 0; i < n; i++) {
    ll s = 0;
    int j0 = j;
    while (j < m && as[i] > s) s += bs[j++];
    if (as[i] != s) { puts("0"); return 0; }

    if (j - j0 > 1) {
      if (j - j0 == as[i]) { // all 1
	int lj = j - j0 - 1;
	p *= invfs[lj] * mi(2).pow(lj);
	l += lj;
      }
      else {
	int k0 = j0, k1 = j;
	while (k0 < j && bs[k0] == 1) k0++;
	while (k1 > j0 && bs[k1 - 1] == 1) k1--;
	if (k1 - k0 > 1) { puts("0"); return 0; }
	int l0 = k0 - j0, l1 = j - k1;
	p *= invfs[l0 + l1] * nck(l0 + l1, l0);
	l += l0 + l1;
      }
    }

    p *= fs[l];

    printf("%d\n", p.v);
  }

  return 0;
}
accuracy: 0.06818181818181818
time_ms: 10
memory_kb: 3752
final_rank: 20

code_snippet: #include <bits/stdc++.h>
#define rep(i,n) for(int i=0;i<(n);i++)

using namespace std;
using ll = long long;
using P = pair<int,int>;
const int mod = 998244353;
const int inf = (1<<30);

const int dy[4] = {-1,0,0,1};
const int dx[4] = {0,-1,1,0};


// BEGIN HERE internal_math

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


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

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

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

            unsigned int umod() const { return _m; }

            unsigned int mul(unsigned int a, unsigned int b) const {
                unsigned long long z = a;
                z *= b;
#ifdef _MSC_VER
                unsigned long long x;
                _umul128(z, im, &x);
#else
                unsigned long long x = (unsigned long long)(((unsigned __int128)(z)*im) >> 64);
#endif
                unsigned long long y = x * _m;
                return (unsigned int)(z - y + (z < y ? _m : 0));
            }
        };

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

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

        template <int n> constexpr bool is_prime = is_prime_constexpr(n);

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

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

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

                auto tmp = s;
                s = t;
                t = tmp;
                tmp = m0;
                m0 = m1;
                m1 = tmp;
            }

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

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

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

                unsigned long long y_max = a * n + b;
                if (y_max < m) break;

                n = (unsigned long long)(y_max / m);
                b = (unsigned long long)(y_max % m);
                std::swap(m, a);
            }
            return ans;
        }
    }
}
// END HERE internal_math


// BEGIN HERE internal_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::condional<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;
    }
}
// END HERE internal_type_traits


// BEGIN HERE modint
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>;
    }

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

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

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

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

            unsigned int val() const { return _v; }

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

            mint& operator+=(const mint& rhs) {
                _v += rhs._v;
                if (_v >= umod()) _v -= umod();
                return *this;
            }

            mint& operator-=(const mint& rhs) {
                _v -= rhs._v;
                if (_v >= umod()) _v += umod();
                return *this;
            }

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

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

            mint pow(long long n) const {
                assert(0 <= n);
                mint x = *this, r = 1;
                while (n) {
                    if (n & 1) r *= x;
                    x *= x;
                    n >>= 1;
                }
                return r;
            }

            mint inv() const {
                if(prime) {
                    assert(_v);
                    return pow(umod() - 2);
                } else {
                    auto eg = internal::inv_gcd(_v, m);
                    assert(eg.first == 1);
                    return eg.second;
                }
            }

            friend mint operator+(const mint& lhs, const mint& rhs) {
                return mint(lhs) += rhs;
            }
            friend mint operator-(const mint& lhs, const mint& rhs) {
                return mint(lhs) -= rhs;
            }
            friend mint operator*(const mint& lhs, const mint& rhs) {
                return mint(lhs) *= rhs;
            }
            friend mint operator/(const mint& lhs, const mint& rhs) {
                return mint(lhs) /= rhs;
            }
            friend bool operator==(const mint& lhs, const mint& rhs) {
                return lhs._v == rhs._v;
            }
            friend bool operator!=(const mint& lhs, const mint& rhs) {
                return lhs._v != rhs._v;
            }
            private:
            unsigned int _v;
            static constexpr unsigned int umod() { return m; }
            static constexpr bool prime = internal::is_prime<m>;
        };

    // dynamic_modintは写経していない

    using modint998244353 = static_modint<998244353>;
    using modint1000000007 = static_modint<1000000007>;

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

}
// END HERE modint

using namespace atcoder;
using mint = modint998244353;


// [1,1,1,5,5,3,3,3,3] -> [(1, 3), (5, 2), (3, 4)]
template <typename T>
decltype(auto) runlength(vector<T> vs) {
    vector<pair<T, int>> es;
    for(auto v:vs) {
        if(es.empty() or es.back().first != v) {
            es.emplace_back(v,0);
        }
        es.back().second++;
    }
    return es;
}



struct Block {
    mint left_count=0;
    mint center=0;
    mint right_count=0;
    ll sum(){
        return (ll)left_count.val() + (ll)center.val() + (ll)right_count.val();
    }
    mint lr(){
        return left_count + right_count;
    }
};


bool is_all_one(const vector<int> &vs) {
    for(const auto &v:vs) {
        if(v != 1) {
            return false;
        }
    }
    return true;
}


int main() {
    int n, m;
    cin>>n>>m;


    // mint(2).pow(20);
    //
    //
    vector<int> a(n);
    for(auto &v:a){
        cin>>v;
    }

    vector<int> b(m);
    for(auto &v:b){
        cin>>v;
    }

    if(n > m) {
        cout << 0 << endl;
        return 0;
    }

    int sum_a = accumulate(a.begin(), a.end(), 0LL);
    int sum_b = accumulate(b.begin(), b.end(), 0LL);
    if(sum_a != sum_b){
        cout << 0 << endl;
        return 0;
    }

    if(is_all_one(b)) {
        // ここになんらかの処理
    }


    int sum = 0;
    int ai = 0;

    vector<Block> bs(n);
    vector<mint> f(100011);
    f[0] = 1;
    rep(i,100010){
        f[i+1] = f[i]*(i+1);
    }
    //cout<<f[2].val()<<endl;
    int i2 = 0;
    for(int i=0;i<n;i++) {
        while(i2 < m && bs[i].sum() < a[i]){
            if(b[i2] == 1){
                if(bs[i].center == 0) bs[i].left_count++;
                else bs[i].right_count++;
            }else{
                if(bs[i].center.val() != 0){
                    cout<<0<<endl;
                    return 0;
                }else bs[i].center = b[i2];
            }
            i2++;
        }
        if(bs[i].sum() != a[i]){
            cout<<"0"<<endl;
            return 0;
        }
    }
    mint ans = 1;
    ////cout<<ans.val()<<"aaaaa"<<endl;
    for(int i = 0; i<n; i++){
        if(bs[i].center.val() != 0){
            ans*=f[bs[i].right_count.val()+bs[i].left_count.val()] /
            (f[bs[i].right_count.val()]*f[bs[i].left_count.val()]);
        }else{
            mint res = 0;
            for(int j = 0; j < bs[i].lr().val(); j++){
                res += (f[bs[i].lr().val()-1]) / (f[j]*f[bs[i].lr().val() - j-1]);
                //cout<<bs[i].lr().val()-1<<" "<<j<<" "<<bs[i].lr().val() - j-1<<endl;
            }
            if(res == 0) continue;
            ans*= res;
        }
    }
    //cout<<ans.val()<<"bbbbb"<<endl;
    int bs_sum = 0;
    for(int i = 0; i<n; i++){
        bs_sum += bs[i].lr().val();
        if(bs[i].center.val() == 0) bs_sum--;
    }
    mint res = f[bs_sum];
    //cout<<"cccc"<<endl;
    for(int i = 0; i<n; i++){

       //cout<<bs[i].lr().val()<<endl;
       if(bs[i].center.val() != 0){
           //cout<<f[bs[i].lr().val()].val()<<endl;
           res /= f[bs[i].lr().val()];
          }
       else {res /= f[bs[i].lr().val() - 1];}
       ////cout<<bs[i].lr().val()<<endl;
    }
     cout<<(ans*res).val()<<endl;

}
accuracy: 1
time_ms: 40
memory_kb: 5316
final_rank: 7

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 + 1 < N ; i++) {
            F.at(i + 1) = mul(F[i], i + 1);
        }

        invF.at(N - 1) = modinv(F.at(N - 1));

        for (int i = N - 1 ; 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 int MOD = 998244353;

int main() {
    ll N, M; cin >> N >> M;
    vector<ll> A(N), B(M);
    for(int i = 0; i < N; i++) cin >> A[i];
    for(int i = 0; i < M; i++) cin >> B[i];

    if(N > M){
        cout << 0 << endl;
        return 0;
    }
    ll tmp = 0;
    for(int i = 0; i < N; i++) tmp += A[i];
    for(int i = 0; i < M; i++) tmp -= B[i];
    if(tmp != 0){
        cout << 0 << endl;
        return 0;
    }

    vector<ll> p2(2e5+10);
    p2[0] = 1;
    for(int i = 0; i < 2e5+5; i++){
        p2[i + 1] = 2 * p2[i] % MOD;    
    }
    BinomMod<MOD> comb((int)2e5+10);

    A.emplace_back((ll)1e14);
    B.emplace_back((ll)1e14);
    ll ans = 1;
    ll idA = 0, L = 0, R = 0, sum = 0; // sum [L, R)
    vector<ll> vals;
    for(R = 0; R <= M;){
        if(sum == A.at(idA)){
            int num_n1 = 0, idn1 = 0;
            for(int j = L; j < R; j++){
                if(B[j] != 1){
                    num_n1++, idn1 = j;    
                }    
            }

            if(num_n1 == 0) {
                ans = (ans * p2[R - L - 1]) % MOD;
            }
            else if(num_n1 == 1) {
                ans = (ans * comb.C(R - L - 1, idn1 - L)) % MOD;
            }
            else{
                cout << 0 << endl;
                return 0;
            }
            if(R - L >= 1) vals.emplace_back(R - L - 1);

            idA++;
            sum = 0;
            L = R;
        }
        else if(sum > A.at(idA)){
            cout << 0 << endl;
            return 0;    
        }
        else{
            sum += B[R];
            R++;
        }
        //cerr << sum << " " << ans << endl;
    }

    ll sumV = 0;
    for(auto it : vals){
        sumV += it;
        //cerr << it << endl;
    }
    ans = ans * comb.Fac(sumV) % MOD;

    for(auto it : vals){
        //cerr << ans << endl;
        ans = ans * comb.Fac(-it) % MOD;
    }

    if(L != M) cout << 0 << endl;
    else cout << ans << endl;
}
accuracy: 1
time_ms: 30
memory_kb: 10708
final_rank: 8

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 modmul(ll a, ll b){
  return f(a * b);
}

ll modadd(ll a,ll b){
  return f(a + b);
}

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

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

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

ll moddiv(ll a,ll b){
  return modmul(a, modinv(b));
}

ll combination(ll a,ll b){
  return moddiv(factorial(a), modmul(factorial(b),factorial(a-b)));
}

ll func(){
  int n;
  int m;
  cin >> n >> m;
  vector<int> as(n);
  vector<int> bs(m);
  for(auto &i:as)cin >> i;
  for(auto &i:bs)cin >> i;
  int itr = 0;
  ll res = 1;
  int cnt = 0;
  for(auto i:as){
    int l = itr;
    int r = itr;
    int sum = 0;
    while(sum != i){
      if(i < sum)return 0;
      if(r == m)return 0;
      sum += bs[r];
      ++r;
    }
    itr = r;
    vector<int> line(bs.begin()+l,bs.begin()+r);
    int maxs = *max_element(line.begin(),line.end());
    {
      int max_cnt = 0;
      for(auto i:line){
        if(i > 1)++max_cnt;
      }
      if(max_cnt > 1)return 0;
    }
    ll x = 0;
    for(int mid=0;mid<line.size();++mid){
      if(line[mid] != maxs)continue;
      int left = mid;
      int right = line.size() - 1 - mid;
      ll add = combination(left + right, left);
      x = modadd(x, add);
    }
    cnt += line.size() - 1;
    res = moddiv(res, factorial(line.size()-1));
    res = modmul(res, x);
  }
  res = modmul(res, factorial(cnt));
  if(itr != m)return 0;
  return res;
}

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

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 modmul(ll a, ll b){
  return f(a * b);
}

ll modadd(ll a,ll b){
  return f(a + b);
}

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

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

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

ll moddiv(ll a,ll b){
  return modmul(a, modinv(b));
}

ll combination(ll a,ll b){
  return moddiv(factorial(a), modmul(factorial(b),factorial(a-b)));
}

ll func(){
  int n;
  int m;
  cin >> n >> m;
  vector<int> as(n);
  vector<int> bs(m);
  for(auto &i:as)cin >> i;
  for(auto &i:bs)cin >> i;
  int itr = 0;
  ll res = 1;
  int cnt = 0;
  for(auto i:as){
    int l = itr;
    int r = itr;
    int sum = 0;
    while(sum != i){
      if(i < sum)return 0;
      if(r == m)return 0;
      sum += bs[r];
      ++r;
    }
    itr = r;
    vector<int> line(bs.begin()+l,bs.begin()+r);
    int maxs = *max_element(line.begin(),line.end());
    {
      int max_cnt = 0;
      for(auto i:line){
        if(i > 1)++max_cnt;
      }
      if(max_cnt > 1)return 0;
    }
    ll x = 0;
    for(int mid=0;mid<line.size();++mid){
      if(line[mid] != maxs)continue;
      int left = mid;
      int right = line.size() - 1 - mid;
      ll add = combination(left + right, left);
      x = modadd(x, add);
    }
    cnt += line.size() - 1;
    res = moddiv(res, factorial(line.size()-1));
    res = modmul(res, x);
  }
  res = modmul(res, factorial(cnt));
  return res;
}

int main(){
  cout << func() << endl;
}
accuracy: 0.9318181818181818
time_ms: 60
memory_kb: 4380
final_rank: 16

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 modmul(ll a, ll b){
  return f(a * b);
}

ll modadd(ll a,ll b){
  return f(a + b);
}

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

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

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

ll moddiv(ll a,ll b){
  return modmul(a, modinv(b));
}

ll combination(ll a,ll b){
  return moddiv(factorial(a), modmul(factorial(b),factorial(a-b)));
}

ll func(){
  int n;
  int m;
  cin >> n >> m;
  vector<int> as(n);
  vector<int> bs(m);
  for(auto &i:as)cin >> i;
  for(auto &i:bs)cin >> i;
  int itr = 0;
  ll res = 1;
  int cnt = 0;
  for(auto i:as){
    int l = itr;
    int r = itr;
    int sum = 0;
    while(sum != i){
      if(r == m)return 0;
      sum += bs[r];
      ++r;
    }
    itr = r;
    vector<int> line(bs.begin()+l,bs.begin()+r);
    int maxs = *max_element(line.begin(),line.end());
    ll x = 0;
    for(int mid=0;mid<line.size();++mid){
      if(line[mid] != maxs)continue;
      int left = mid;
      int right = line.size() - 1 - mid;
      ll add = combination(left + right, left);
      x = modadd(x, add);
    }
    cnt += line.size() - 1;
    res = moddiv(res, factorial(line.size()-1));
    res = modmul(res, x);
  }
  res = modmul(res, factorial(cnt));
  return res;
}

int main(){
  cout << func() << endl;
}
accuracy: 0.8636363636363636
time_ms: 60
memory_kb: 4436
final_rank: 17

code_snippet: #ifndef CLASS_MODINT
#define CLASS_MODINT

#include <cstdint>

template <std::uint32_t mod>
class modint {
private:
	std::uint32_t n;
public:
	modint() : n(0) {};
	modint(std::int64_t n_) : n((n_ >= 0 ? n_ : mod - (-n_) % mod) % mod) {};
	static constexpr std::uint32_t get_mod() { return mod; }
	std::uint32_t get() const { return n; }
	bool operator==(const modint& m) const { return n == m.n; }
	bool operator!=(const modint& m) const { return n != m.n; }
	modint& operator+=(const modint& m) { n += m.n; n = (n < mod ? n : n - mod); return *this; }
	modint& operator-=(const modint& m) { n += mod - m.n; n = (n < mod ? n : n - mod); return *this; }
	modint& operator*=(const modint& m) { n = std::uint64_t(n) * m.n % mod; return *this; }
	modint operator+(const modint& m) const { return modint(*this) += m; }
	modint operator-(const modint& m) const { return modint(*this) -= m; }
	modint operator*(const modint& m) const { return modint(*this) *= m; }
	modint inv() const { return (*this).pow(mod - 2); }
	modint pow(std::uint64_t b) const {
		modint ans = 1, m = modint(*this);
		while (b) {
			if (b & 1) ans *= m;
			m *= m;
			b >>= 1;
		}
		return ans;
	}
};

#endif // CLASS_MODINT

#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
using mint = modint<998244353>;

mint subsolve(const std::vector<int>& seq) {
	int n = seq.size();
	vector<mint> fact(n + 1);
	fact[0] = 1;
	for (int i = 1; i <= n; i++) {
		fact[i] = fact[i - 1] * i;
	}
	int pos = -1;
	for (int i = 0; i < n; i++) {
		if (seq[i] != 1) {
			if (pos != -1) {
				return mint(0);
			}
			pos = i;
		}
	}
	if (pos != -1) {
		return fact[n - 1] * fact[pos].inv() * fact[(n - 1) - pos].inv();
	}
	return mint(2).pow(n - 1);
}

int main() {
	int N, M;
	cin >> N >> M;
	vector<long long> A(N), B(M);
	for (int i = 0; i < N; i++) {
		cin >> A[i];
	}
	for (int i = 0; i < M; i++) {
		cin >> B[i];
	}
	int pos = 0; long long cursum = 0;
	bool valid = true;
	vector<int> spl = { 0 };
	for (int i = 0; i < N; i++) {
		while (pos < M && cursum < A[i]) {
			cursum += B[pos];
			pos += 1;
		}
		if (cursum != A[i]) {
			valid = false;
			break;
		}
		spl.push_back(pos);
		cursum = 0;
	}
	if (pos != M) {
		valid = false;
	}
	if (!valid) {
		cout << 0 << endl;
	}
	else {
		vector<mint> fact(M + 1);
		fact[0] = 1;
		for (int i = 1; i <= M; i++) {
			fact[i] = fact[i - 1] * i;
		}
		mint answer = 1;
		for (int i = 0; i < N; i++) {
			answer *= subsolve(vector<int>(B.begin() + spl[i], B.begin() + spl[i + 1]));
		}
		answer *= fact[M - N];
		for (int i = 0; i < N; i++) {
			answer *= fact[spl[i + 1] - spl[i] - 1].inv();
		}
		cout << answer.get() << endl;
	}
	return 0;
}
accuracy: 1
time_ms: 50
memory_kb: 5408
final_rank: 9

code_snippet: #include <iostream>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <vector>
#include <numeric>
#include <algorithm>
#include <queue>
#include <string>

constexpr int MOD = 998244353;
long long int pow_mod(long long int base, int exp) {
	long long int result = 1LL;
	base %= MOD;
	while (exp > 0) {
		if ((exp & 1) == 1) {
			result = result * base % MOD;
		}
		base = base * base % MOD;
		exp >>= 1;
	}
	return result;
}
long long int factorial(const int n) {
	static bool initialized = false;
	static std::vector<long long int> cache;
	if (initialized) {
		return cache[n];
	}
	initialized = true;
	cache.resize(100001, 1);
	for (auto i = 2; i < cache.size(); ++i) {
		cache[i] = i * cache[i - 1] % MOD;
	}
	return cache[n];
}
long long int inverse_factorial(const int n) {
	static bool initialized = false;
	static std::vector<long long int> cache;
	if (initialized) {
		return cache[n];
	}
	initialized = true;
	cache.resize(100001, 1);
	cache.back() = pow_mod(factorial(cache.size() - 1), MOD - 2);
	for (auto i = cache.size() - 1; i >= 2; --i) {
		cache[i - 1] = i * cache[i] % MOD;
	}
	return cache[n];
}
long long int combination(const int n, const int r) {
	return factorial(n) * inverse_factorial(r) % MOD * inverse_factorial(n - r) % MOD;
}
long long int calc_pattern(const std::vector<int> num) {
	const auto pos = std::find_if(num.begin(), num.end(), [](const int v) {return v != 1; });
	if (pos == num.end()) {
		return pow_mod(2, num.size() - 1);
	}
	const auto next = std::find_if(std::next(pos), num.end(), [](const int v) {return v != 1; });
	if (next != num.end()) {
		return 0;
	}
	const auto left = std::distance(num.begin(), pos);
	return combination(num.size() - 1, left);
}
int main() {
	int n, m; std::cin >> n >> m;
	std::vector<int> a(n), b(m);
	for (auto& v : a) {
		std::cin >> v;
	}
	for (auto& v : b) {
		std::cin >> v;
	}
	int i = 0;
	long long int result = 1LL;
	int count = 0;
	for (const auto v : a) {
		auto sum = 0;
		std::vector<int> sub_b;
		while (i < m && sum < v) {
			sub_b.push_back(b[i]);
			sum += b[i++];
		}
		if (sum != v) {
			result = 0;
			break;
		}
		const auto pattern = calc_pattern(sub_b) * combination(count + sub_b.size() - 1, count) % MOD;
		count += sub_b.size() - 1;
		result = result * pattern % MOD;
	}
	if (i != m) {
		result = 0;
	}
	std::cout << result << '\n';
}
accuracy: 1
time_ms: 30
memory_kb: 5248
final_rank: 6

code_snippet: #include <iostream>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <vector>
#include <numeric>
#include <algorithm>
#include <queue>
#include <string>

constexpr int MOD = 998244353;
long long int pow_mod(long long int base, int exp) {
	long long int result = 1LL;
	base %= MOD;
	while (exp > 0) {
		if ((exp & 1) == 1) {
			result = result * base % MOD;
		}
		base = base * base % MOD;
		exp >>= 1;
	}
	return result;
}
long long int factorial(const int n) {
	static bool initialized = false;
	static std::vector<long long int> cache;
	if (initialized) {
		return cache[n];
	}
	initialized = true;
	cache.resize(100001, 1);
	for (auto i = 2; i < cache.size(); ++i) {
		cache[i] = i * cache[i - 1] % MOD;
	}
	return cache[n];
}
long long int inverse_factorial(const int n) {
	static bool initialized = false;
	static std::vector<long long int> cache;
	if (initialized) {
		return cache[n];
	}
	initialized = true;
	cache.resize(100001, 1);
	cache.back() = pow_mod(factorial(cache.size() - 1), MOD - 2);
	for (auto i = cache.size() - 1; i >= 2; --i) {
		cache[i - 1] = i * cache[i] % MOD;
	}
	return cache[n];
}
long long int combination(const int n, const int r) {
	return factorial(n) * inverse_factorial(r) % MOD * inverse_factorial(n - r) % MOD;
}
long long int calc_pattern(const std::vector<int> num) {
	const auto pos = std::find_if(num.begin(), num.end(), [](const int v) {return v != 1; });
	if (pos == num.end()) {
		return pow_mod(2, num.size() - 1);
	}
	const auto sum = std::accumulate(num.begin(), num.end(), 0LL);
	if (sum != num.size() - 1 + *pos) {
		return 0;
	}
	const auto left = std::distance(num.begin(), pos);
	return combination(num.size() - 1, left);
}
int main() {
	int n, m; std::cin >> n >> m;
	std::vector<int> a(n), b(m);
	for (auto& v : a) {
		std::cin >> v;
	}
	for (auto& v : b) {
		std::cin >> v;
	}
	int i = 0;
	long long int result = 1LL;
	int count = 0;
	for (const auto v : a) {
		auto sum = 0;
		std::vector<int> sub_b;
		while (i < m && sum < v) {
			sub_b.push_back(b[i]);
			sum += b[i++];
		}
		if (sum != v) {
			result = 0;
			break;
		}
		const auto pattern = calc_pattern(sub_b) * combination(count + sub_b.size() - 1, count) % MOD;
		count += sub_b.size() - 1;
		result = result * pattern % MOD;
	}
	std::cout << result << '\n';
}
accuracy: 0.9318181818181818
time_ms: 30
memory_kb: 5284
final_rank: 15

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
//#define MOD 1000000007
#define EPS 0.000000001



#define MOD 998244353
#define SIZE 1000005
#define SIZE2 100005


ll fact[SIZE],inv_fact[SIZE];
ll POW[SIZE];
ll A[SIZE2],B[SIZE2];

ll mod_pow(ll x,ll count, ll mod){

	if(count == 0)return 1;
	ll ret = mod_pow(((x%mod)*(x%mod))%mod,count/2,mod);
	if(count%2 == 1){

		ret = ((ret%mod)*(x%mod))%mod;
	}
	return ret;
}


ll euler_phi(ll num){

	 ll ret = num;

	 for(ll i = 2; i*i <= num;  i++){
			if(num%i == 0) {
				  ret  = ret/i*(i-1);
				  while(num%i == 0)num /= i;
			}
	  }
	  if(num != 1) ret = ret/num*(num-1);
	  return ret;
}


ll extgcd(ll a,ll b,ll &x,ll &y){
	ll d = a;
	if(b != 0){
		d = extgcd(b,a%b,y,x);
		y -= (a/b)*x;
	}else{
		x = 1;
		y = 0;
	}
	return d;
}

ll mod_inverse(ll a,ll m){
    ll x,y;
    extgcd(a,m,x,y);
    return (m+x%m)%m;
}

ll nCk(ll n,ll k){

	if(k > n)return 0;

	ll ret = fact[n]*inv_fact[k];
	ret %= MOD;
	ret *= inv_fact[n-k];

	return ret%MOD;
}

ll nPk(ll n,ll k){

	if(k > n)return 0;

	ll ret = fact[n]*inv_fact[n-k];

	return ret%MOD;
}



int main(){

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

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

	fact[0] = 1;
	for(ll i = 1; i < SIZE; i++){
		fact[i] = i*fact[i-1];
		fact[i] %= MOD;
	}
	inv_fact[SIZE-1] = mod_inverse(fact[SIZE-1],MOD);
	for(ll i = SIZE-1; i >= 1; i--){

		inv_fact[i-1] = inv_fact[i]*i;
		inv_fact[i-1] %= MOD;
	}

	ll N,M;
	scanf("%lld %lld",&N,&M);
	if(N > M){

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

	ll sum_A = 0,sum_B = 0;

	for(ll i = 0; i < N; i++){

		scanf("%lld",&A[i]);
		sum_A += A[i];
	}

	for(ll i = 0; i < M; i++){

		scanf("%lld",&B[i]);
		sum_B += B[i];
	}
	if(sum_A != sum_B){

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

	int ind = 0;
	ll ans = 1;

	vector<ll> vec;

	for(ll i = 0; i < N; i++){

		if(ind == M){

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

		int L = ind; //区間の左端

		if(B[ind] > A[i]){

			printf("0\n");
			return 0;
		}else if(B[ind] == A[i]){

			ind++;
			continue;
		}

		int over1 = 0; //1より大きい数の個数
		int pos = -1; //■1より大きい数の位置(もしあれば)

		ll sum = B[ind];
		if(B[ind] > 1){

			over1 = 1;
			pos = ind;
		}

		ind++;

		while(sum < A[i] && ind < M){

			sum += B[ind];
			if(B[ind] > 1){

				over1++;
				pos = ind;

				if(over1 > 1){

					printf("0\n");
					return 0;
				}
			}
			ind++;
		}
		if(sum != A[i]){

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

		vec.push_back(ind-L-1); //■■数字自体の、操作順を考える■■

		if(over1 == 0){ //全て1

			ll len = ind-L; //区間長さ
			ans *= POW[len-1];
			ans %= MOD;

		}else{ //1より大きい数が1つだけあり

			ll num_L = pos-L;
			ll num_R = (ind-pos-1);

			ans *= nCk(num_L+num_R,num_L);
			ans %= MOD;
		}
	}

	ans *= fact[M-N]; //■■数字自体の、操作順を考える■■
	ans %= MOD;

	for(ll i = 0; i < vec.size(); i++){

		ans *= inv_fact[vec[i]];
		ans %= MOD;
	}

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

	return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 28044
final_rank: 11

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
//#define MOD 1000000007
#define EPS 0.000000001



#define MOD 998244353
#define SIZE 1000005
#define SIZE2 100005


ll fact[SIZE],inv_fact[SIZE];
ll POW[SIZE];
ll A[SIZE2],B[SIZE2];

ll mod_pow(ll x,ll count, ll mod){

	if(count == 0)return 1;
	ll ret = mod_pow(((x%mod)*(x%mod))%mod,count/2,mod);
	if(count%2 == 1){

		ret = ((ret%mod)*(x%mod))%mod;
	}
	return ret;
}


ll euler_phi(ll num){

	 ll ret = num;

	 for(ll i = 2; i*i <= num;  i++){
			if(num%i == 0) {
				  ret  = ret/i*(i-1);
				  while(num%i == 0)num /= i;
			}
	  }
	  if(num != 1) ret = ret/num*(num-1);
	  return ret;
}


ll extgcd(ll a,ll b,ll &x,ll &y){
	ll d = a;
	if(b != 0){
		d = extgcd(b,a%b,y,x);
		y -= (a/b)*x;
	}else{
		x = 1;
		y = 0;
	}
	return d;
}

ll mod_inverse(ll a,ll m){
    ll x,y;
    extgcd(a,m,x,y);
    return (m+x%m)%m;
}

ll nCk(ll n,ll k){

	if(k > n)return 0;

	ll ret = fact[n]*inv_fact[k];
	ret %= MOD;
	ret *= inv_fact[n-k];

	return ret%MOD;
}

ll nPk(ll n,ll k){

	if(k > n)return 0;

	ll ret = fact[n]*inv_fact[n-k];

	return ret%MOD;
}



int main(){

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

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

	fact[0] = 1;
	for(ll i = 1; i < SIZE; i++){
		fact[i] = i*fact[i-1];
		fact[i] %= MOD;
	}
	inv_fact[SIZE-1] = mod_inverse(fact[SIZE-1],MOD);
	for(ll i = SIZE-1; i >= 1; i--){

		inv_fact[i-1] = inv_fact[i]*i;
		inv_fact[i-1] %= MOD;
	}

	ll N,M;
	scanf("%lld %lld",&N,&M);
	if(N > M){

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

	ll sum_A = 0,sum_B = 0;

	for(ll i = 0; i < N; i++){

		scanf("%lld",&A[i]);
		sum_A += A[i];
	}

	for(ll i = 0; i < M; i++){

		scanf("%lld",&B[i]);
		sum_B += B[i];
	}
	if(sum_A != sum_B){

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

	int ind = 0;
	ll ans = 1;

	vector<ll> vec;

	for(ll i = 0; i < N; i++){

		//printf("\ni:%lld\n",i);

		if(ind == M){

			//printf("indがM\n");
			printf("0\n");
			return 0;
		}

		int L = ind; //区間の左端

		if(B[ind] > A[i]){

			//printf("初項がA[i]より大\n");
			printf("0\n");
			return 0;
		}else if(B[ind] == A[i]){

			ind++;
			continue;
		}

		int over1 = 0; //1より大きい数の個数
		int pos = -1; //■1より大きい数の位置(もしあれば)

		ll sum = B[ind];
		if(B[ind] > 1){

			over1 = 1;
			pos = ind;
		}

		ind++;

		while(sum < A[i] && ind < M){

			//printf("sum:%lld ind:%d\n",sum,ind);

			sum += B[ind];
			if(B[ind] > 1){

				over1++;
				pos = ind;

				if(over1 > 1){
					//printf("1より大きいのが2つ以上\n");
					printf("0\n");
					return 0;
				}
			}
			ind++;
		}
		if(sum != A[i]){
			//printf("総和がA[i]と異なる\n");
			printf("0\n");
			return 0;
		}

		vec.push_back(ind-L-1); //■■数字自体の、操作順を考える■■

		if(over1 == 0){ //全て1

			//printf("全て1:区間長:%d\n",ind-L);
			ll len = ind-L; //区間長さ
			ans *= POW[len-1];
			ans %= MOD;

		}else{ //1より大きい数が1つだけあり

			ll num_L = pos-L;
			ll num_R = (ind-pos-1);

			//printf("1より大きい数が1つだけあり l;%lld r:%lld\n",num_L,num_R);

			ans *= nCk(num_L+num_R,num_L);
			ans %= MOD;
		}
	}

	ans *= fact[M-N];
	ans %= MOD;

	for(ll i = 0; i < vec.size(); i++){

		ans *= inv_fact[vec[i]];
		ans %= MOD;
	}

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

	return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 28132
final_rank: 12

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
//#define MOD 1000000007
#define EPS 0.000000001



#define MOD 998244353
#define SIZE 1000005
#define SIZE2 100005


ll fact[SIZE],inv_fact[SIZE];
ll POW[SIZE];
ll A[SIZE2],B[SIZE2];

ll mod_pow(ll x,ll count, ll mod){

	if(count == 0)return 1;
	ll ret = mod_pow(((x%mod)*(x%mod))%mod,count/2,mod);
	if(count%2 == 1){

		ret = ((ret%mod)*(x%mod))%mod;
	}
	return ret;
}


ll euler_phi(ll num){

	 ll ret = num;

	 for(ll i = 2; i*i <= num;  i++){
			if(num%i == 0) {
				  ret  = ret/i*(i-1);
				  while(num%i == 0)num /= i;
			}
	  }
	  if(num != 1) ret = ret/num*(num-1);
	  return ret;
}


ll extgcd(ll a,ll b,ll &x,ll &y){
	ll d = a;
	if(b != 0){
		d = extgcd(b,a%b,y,x);
		y -= (a/b)*x;
	}else{
		x = 1;
		y = 0;
	}
	return d;
}

ll mod_inverse(ll a,ll m){
    ll x,y;
    extgcd(a,m,x,y);
    return (m+x%m)%m;
}

ll nCk(ll n,ll k){

	if(k > n)return 0;

	ll ret = fact[n]*inv_fact[k];
	ret %= MOD;
	ret *= inv_fact[n-k];

	return ret%MOD;
}

ll nPk(ll n,ll k){

	if(k > n)return 0;

	ll ret = fact[n]*inv_fact[n-k];

	return ret%MOD;
}



int main(){

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

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

	fact[0] = 1;
	for(ll i = 1; i < SIZE; i++){
		fact[i] = i*fact[i-1];
		fact[i] %= MOD;
	}
	inv_fact[SIZE-1] = mod_inverse(fact[SIZE-1],MOD);
	for(ll i = SIZE-1; i >= 1; i--){

		inv_fact[i-1] = inv_fact[i]*i;
		inv_fact[i-1] %= MOD;
	}

	ll N,M;
	scanf("%lld %lld",&N,&M);
	if(N > M){

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

	ll sum_A = 0,sum_B = 0;

	for(ll i = 0; i < N; i++){

		scanf("%lld",&A[i]);
		sum_A += A[i];
	}

	for(ll i = 0; i < M; i++){

		scanf("%lld",&B[i]);
		sum_B += B[i];
	}
	if(sum_A != sum_B){

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

	int ind = 0;
	ll ans = 1;
	for(ll i = 0; i < N; i++){

		//printf("\ni:%lld\n",i);

		if(ind == M){

			//printf("indがM\n");
			printf("0\n");
			return 0;
		}

		ll L = ind; //区間の左端

		if(B[ind] > A[i]){

			//printf("初項がA[i]より大\n");
			printf("0\n");
			return 0;
		}else if(B[ind] == A[i]){

			ind++;
			continue;
		}

		int over1 = 0; //1より大きい数の個数
		int pos = -1; //■1より大きい数の位置(もしあれば)

		ll sum = B[ind];
		if(B[ind] > 1){

			over1 = 1;
			pos = ind;
		}

		ind++;

		while(sum < A[i] && ind < M){

			//printf("sum:%lld ind:%d\n",sum,ind);

			sum += B[ind];
			if(B[ind] > 1){

				over1++;
				pos = ind;

				if(over1 > 1){
					//printf("1より大きいのが2つ以上\n");
					printf("0\n");
					return 0;
				}
			}
			if(sum > A[i]){
				//printf("sumがA[i]より第\n");
				printf("0\n");
				return 0;
			}
			ind++;
		}
		if(sum != A[i]){
			//printf("総和がA[i]と異なる\n");
			printf("0\n");
			return 0;
		}
		if(over1 == 0){ //全て1

			//printf("全て1:区間長:%d\n",ind-L);
			ll len = ind-L; //区間長さ
			ans *= POW[len-1];
			ans %= MOD;

		}else{ //1より大きい数が1つだけあり

			ll num_L = pos-L;
			ll num_R = (ind-pos-1);

			//printf("1より大きい数が1つだけあり l;%lld r:%lld\n",num_L,num_R);

			ans *= nCk(num_L+num_R,num_L);
			ans %= MOD;
		}
	}

	if(ind < M){

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

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

	return 0;
}
accuracy: 0.09090909090909091
time_ms: 10
memory_kb: 26568
final_rank: 18

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
//#define MOD 1000000007
#define EPS 0.000000001



#define MOD 998244353
#define SIZE 1000005
#define SIZE2 100005


ll fact[SIZE],inv_fact[SIZE];
ll POW[SIZE];
ll A[SIZE2],B[SIZE2];

ll mod_pow(ll x,ll count, ll mod){

	if(count == 0)return 1;
	ll ret = mod_pow(((x%mod)*(x%mod))%mod,count/2,mod);
	if(count%2 == 1){

		ret = ((ret%mod)*(x%mod))%mod;
	}
	return ret;
}


ll euler_phi(ll num){

	 ll ret = num;

	 for(ll i = 2; i*i <= num;  i++){
			if(num%i == 0) {
				  ret  = ret/i*(i-1);
				  while(num%i == 0)num /= i;
			}
	  }
	  if(num != 1) ret = ret/num*(num-1);
	  return ret;
}


ll extgcd(ll a,ll b,ll &x,ll &y){
	ll d = a;
	if(b != 0){
		d = extgcd(b,a%b,y,x);
		y -= (a/b)*x;
	}else{
		x = 1;
		y = 0;
	}
	return d;
}

ll mod_inverse(ll a,ll m){
    ll x,y;
    extgcd(a,m,x,y);
    return (m+x%m)%m;
}

ll nCk(ll n,ll k){

	if(k > n)return 0;

	ll ret = fact[n]*inv_fact[k];
	ret %= MOD;
	ret *= inv_fact[n-k];

	return ret%MOD;
}

ll nPk(ll n,ll k){

	if(k > n)return 0;

	ll ret = fact[n]*inv_fact[n-k];

	return ret%MOD;
}



int main(){

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

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

	fact[0] = 1;
	for(ll i = 1; i < SIZE; i++){
		fact[i] = i*fact[i-1];
		fact[i] %= MOD;
	}
	inv_fact[SIZE-1] = mod_inverse(fact[SIZE-1],MOD);
	for(ll i = SIZE-1; i >= 1; i--){

		inv_fact[i-1] = inv_fact[i]*i;
		inv_fact[i-1] %= MOD;
	}

	ll N,M;
	scanf("%lld %lld",&N,&M);

	ll sum_A = 0,sum_B = 0;

	for(ll i = 0; i < N; i++){

		scanf("%lld",&A[i]);
		sum_A += A[i];
	}

	for(ll i = 0; i < M; i++){

		scanf("%lld",&B[i]);
		sum_B += B[i];
	}
	if(sum_A != sum_B){

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

	int ind = 0;
	ll ans = 1;
	for(ll i = 0; i < N; i++){

		//printf("\ni:%lld\n",i);

		if(ind == M){

			//printf("indがM\n");
			printf("0\n");
			return 0;
		}

		ll L = ind; //区間の左端

		if(B[ind] > A[i]){

			//printf("初項がA[i]より大\n");
			printf("0\n");
			return 0;
		}else if(B[ind] == A[i]){

			ind++;
			continue;
		}

		int over1 = 0; //1より大きい数の個数
		int pos = -1; //■1より大きい数の位置(もしあれば)

		ll sum = B[ind];
		if(B[ind] > 1){

			over1 = 1;
			pos = ind;
		}

		ind++;

		while(sum < A[i] && ind < M){

			//printf("sum:%lld ind:%d\n",sum,ind);

			sum += B[ind];
			if(B[ind] > 1){

				over1++;
				pos = ind;

				if(over1 > 1){
					//printf("1より大きいのが2つ以上\n");
					printf("0\n");
					return 0;
				}
			}
			if(sum > A[i]){
				//printf("sumがA[i]より第\n");
				printf("0\n");
				return 0;
			}
			ind++;
		}
		if(sum != A[i]){
			//printf("総和がA[i]と異なる\n");
			printf("0\n");
			return 0;
		}
		if(over1 == 0){ //全て1

			//printf("全て1:区間長:%d\n",ind-L);
			ll len = ind-L; //区間長さ
			ans *= POW[len-1];
			ans %= MOD;

		}else{ //1より大きい数が1つだけあり

			ll num_L = pos-L;
			ll num_R = (ind-pos-1);

			//printf("1より大きい数が1つだけあり l;%lld r:%lld\n",num_L,num_R);

			ans *= nCk(num_L+num_R,num_L);
			ans %= MOD;
		}
	}

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

	return 0;
}
accuracy: 0.09090909090909091
time_ms: 10
memory_kb: 26648
final_rank: 19