// -fsanitize=undefined,
//#define _GLIBCXX_DEBUG
#pragma GCC target("avx2")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <queue>
#include <algorithm>
#include <cmath>
#include <iomanip>
#include <random>
#include <stdio.h>
#include <fstream>
#include <functional>
#include <cassert>
#include <unordered_map>
#include <bitset>
#include <atcoder/all>
using namespace std;
using namespace atcoder;
#define rep(i,n) for (int i=0;i<n;i+=1)
#define rrep(i,n) for (int i=n-1;i>-1;i--)
#define pb push_back
#define all(x) (x).begin(), (x).end()
template<class T>
using vec = vector<T>;
template<class T>
using vvec = vec<vec<T>>;
template<class T>
using vvvec = vec<vvec<T>>;
using ll = long long;
using pii = pair<int,int>;
using pll = pair<ll,ll>;
template<class T>
bool chmin(T &a, T b){
if (a>b){
a = b;
return true;
}
return false;
}
template<class T>
bool chmax(T &a, T b){
if (a<b){
a = b;
return true;
}
return false;
}
template<class T>
T sum(vec<T> x){
T res=0;
for (auto e:x){
res += e;
}
return res;
}
template<class T>
void printv(vec<T> x){
for (auto e:x){
cout<<e<<" ";
}
cout<<endl;
}
template<class T>
ostream& operator<<(ostream& os, const vec<T>& A){
os << "[";
rep(i,A.size()){
os << A[i];
if (i!=A.size()-1){
os << ", ";
}
}
os << "]" ;
return os;
}
template<class T,class U>
ostream& operator<<(ostream& os, const pair<T,U>& A){
os << "(" << A.first <<", " << A.second << ")";
return os;
}
template<class T>
ostream& operator<<(ostream& os, const set<T>& S){
os << "set{";
for (auto a:S){
os << a;
auto it = S.find(a);
it++;
if (it!=S.end()){
os << ", ";
}
}
os << "}";
return os;
}
using mint = modint998244353;
ostream& operator<<(ostream& os, const mint& a){
os << a.val();
return os;
}
const int M = 2000;
mint g1[M],g2[M],inverse[M];
void init_comb(){
g1[0] = 1; g1[1] = 1;
g2[0] = 1; g2[1] = 1;
inverse[1] = 1;
for (int n=2;n<M;n++){
g1[n] = g1[n-1] * n;
inverse[n] = (-inverse[998244353%n] * (998244353/n));
assert (inverse[n] * n == mint(1));
g2[n] = g2[n-1] * inverse[n];
}
}
mint comb(int n,int r){
if (r < 0 || n < r) return 0;
return g1[n] * g2[r] * g2[n-r];
}
void solve(){
int N,M;
cin>>N>>M;
vector<int> A(M),B(M);
for (int i=0;i<M;i++) cin>>A[i];
for (int i=0;i<M;i++) cin>>B[i];
vector<int> C(M);
for (int i=0;i<M;i++) C[i] = A[i]-B[i];
swap(B,C);
int need_sum = accumulate(all(C),0);
int ALL_N = accumulate(all(A),0);
vector<int> G(1<<M,accumulate(all(B),0));
/*G[S]:i in {1,2,...,N}/Sに対するB[i]の和*/
for (int S=0;S<(1<<M);S++){
for (int i=0;i<M;i++){
if ((S>>i) & 1) G[S] -= B[i];
}
}
vector<int> F(1<<M,0);
/*F[S]:i in S に対する C[i]の和*/
for (int S=0;S<(1<<M);S++){
for (int i=0;i<M;i++){
if ((S>>i) & 1) F[S] += C[i];
}
}
vector<int> H(1<<M,0);
for (int S=0;S<(1<<M);S++){
for (int i=0;i<M;i++){
if ((S>>i) & 1) H[S] += B[i];
}
}
vector<vector<mint>> dp_not_complete(1<<M);
/*dp[S]:i in Sに対する x^k comb(a_i,k) for k in 0,1,2,...,C[i]-1の積*/
dp_not_complete[0] = {1};
for (int n=0;n<M;n++){
vector<mint> f(A[n]+1,0);
for (int k=0;k<C[n];k++){
f[k] = comb(A[n],k);
}
for (int S=(1<<n);S<(1<<(n+1));S++){
dp_not_complete[S] = convolution(dp_not_complete[S-(1<<n)],f);
}
}
vector<vector<mint>> dp_complete(1<<M,vector<mint>(need_sum+1,0));
/*
dp[S][n]->dp[S+{k}][n'](n < n')
comb(n'-F[S]-1,C[k]-1) * g2[G[S]+need_sum-n] * g1[G[S]+need_sum-n'] * g1[A[k]] * g2[B[k]]
*/
int start_set = 0;
for (int i=0;i<M;i++){
if (C[i] == 0){
start_set |= (1<<i);
}
}
dp_complete[start_set][0] = 1;
for (int S=0;S<(1<<M);S++){
for (int k=0;k<M;k++){
if ((S>>k) & 1) continue;
vector<mint> tmp = {all(dp_complete[S])};
for (int n=0;n<=need_sum;n++){
tmp[n] *= g2[G[S]+need_sum-n];
}
for (int n=0;n<need_sum;n++){
tmp[n+1] += tmp[n];
}
for (int n=1;n<=need_sum;n++){
dp_complete[S^(1<<k)][n] += tmp[n-1] * g1[G[S]+need_sum-n] * g1[A[k]] * g2[B[k]] * comb(n-F[S]-1,C[k]-1);
}
}
}
for (int S=0;S<(1<<M);S++){
for (int i=0;i<int(dp_not_complete[S].size());i++){
dp_not_complete[S][i] *= g1[i];
}
}
mint res = 0;
for (int S=0;S<(1<<M)-1;S++){
int not_complete_set = ((1<<M)-1) ^ S;
mint tmp = 0;
for (int j=0;j<int(dp_not_complete[not_complete_set].size());j++){
dp_not_complete[not_complete_set][j] *= g1[G[S]+need_sum-(F[S]+j)] * (inverse[ALL_N-(F[S]+j)-H[S]] * (ALL_N-(F[S]+j)));
}
for (int j=int(dp_not_complete[not_complete_set].size())-2;0<=j;j--){
dp_not_complete[not_complete_set][j] += dp_not_complete[not_complete_set][j+1];
}
for (int i=F[S];i<=need_sum;i++){
int lower = i-F[S];
res += dp_complete[S][i] * g2[G[S]+need_sum-i] * dp_not_complete[not_complete_set][lower];
}
//cout << S << endl;
//cout << dp_complete[S] << " " << dp_not_complete[not_complete_set] << endl;
//cout << tmp << endl;
}
cout << res.val() << "\n";
}
int main(){
ios::sync_with_stdio(false);
std::cin.tie(nullptr);
init_comb();
int T;
T = 1;
while (T--){
solve();
}
}