Problem:
Quiz Contest
The final round of the annual World Quiz Contest is now at the climax!
In this round, questions are asked one by one, and the competitor correctly answering the goal number of questions first will be the champion. Many questions have already been asked and answered. The numbers of questions correctly answered so far by competitors may differ, and thus the numbers of additional questions to answer correctly to win may be different.
The questions elaborated by the judge crew are quite difficult, and the competitors have completely distinct areas of expertise. Thus, for each question, exactly one competitor can find the correct answer.
Who becomes the champion depends on the order of the questions asked. The judge crew know all the questions and who can answer which, but they do not know the order of the remaining questions, as the questions have been randomly shuffled. To help the judge crew guess the champion of this year, count the number of possible orders of the remaining questions that would make each competitor win. Note that the orders of the questions left unused after the decision of the champion should also be considered.
Input
The input consists of a single test case of the following format.
$n$ $m$
$a_1$ ... $a_n$
$b_1$ ... $b_n$
Here, $n$ is the number of competitors and $m$ is the number of remaining questions. Both $n$ and $m$ are integers satisfying $1 \leq n \leq m \leq 2 \times 10^5$. Competitors are numbered $1$ through $n$. The following line contains $n$ integers, $a_1, ...  , a_n$, meaning that the number of remaining questions that the competitor $i$ can answer correctly is $a_i$, where $\sum_{i=1}^n a_i = m$ holds. The last line contains $n$ integers, $b_1, ... , b_n$, meaning that the competitor $i$ has to answer $b_i$ more questions correctly to win. $1 \leq b_i \leq a_i$ holds.
Output
Let $c_i$ be the number of question orders that make the competitor $i$ the champion. Output $n$ lines, each containing an integer. The number on the $i$-th line should be $c_i$ modulo a prime number $998 244 353 = 2^{23} \times 7 \times 17 + 1$. Note that $\sum_{i=1}^n c_i = m!$ holds.
Sample Input 1
2 4
2 2
1 2
Sample Output 1
20
4
Sample Input 2
4 6
1 1 2 2
1 1 1 2
Sample Output 2
168
168
336
48
Sample Input 3
4 82
20 22 12 28
20 22 7 8
Sample Output 3
746371221
528486621
148054814
913602744

Submitted solutions:

code_snippet: #include <iostream>
#include <vector>
#include <algorithm>
#include <utility>
using namespace std;

using ll = long long;
#define rep(i,n) for(ll i=0; i<ll(n); i++)

const int MOD = 998244353;

struct Modint {
    int x;
    Modint() : x(0) {}
    Modint(int y) : x(y%MOD) { if(x < 0) x += MOD; }
    Modint& operator+=(Modint r){ x += r.x; if(x >= MOD){ x-=MOD; } return *this; }
    Modint& operator-=(Modint r){ x -= r.x; if(x < 0){ x+=MOD; } return *this; }
    Modint& operator*=(Modint r){ x = ll(x) * r.x % MOD; return *this; }
    Modint operator+(Modint r) const { auto a = *this; a += r; return a; }
    Modint operator-(Modint r) const { auto a = *this; a -= r; return a; }
    Modint operator*(Modint r) const { auto a = *this; a *= r; return a; }
    Modint pow(ll i) const {
        Modint a = *this;
        Modint r = 1;
        while(i){
            if(i%2) r *= a;
            a *= a;
            i /= 2;
        }
        return r;
    }
    Modint inv() const { return pow(MOD-2); }
};

vector<Modint> it;

void ntt(int n, vector<Modint>& a){
    for(int h=n/2; h>=1; h/=2){
        Modint cy = 1;
        for(int s=0; s<n; s+=h*2){
            for(int t=0; t<h; t++){
                auto x = a[s+t];
                auto y = a[s+t+h];
                a[s+t] = x + y * cy;
                a[s+t+h] = x - y * cy;
            }
            cy *= it[__builtin_ctz(s / h / 2 + 1)];
        }
    }
    int j = 0;
    for(int i=1; i<n; i++){
        for(int f=n/2; f>=1; f>>=1){
            j ^= f;
            if(j&f) break;
        }
        if(i < j) swap(a[i], a[j]);
    }
}

void intt(int n, vector<Modint>& a){
    ntt(n, a);
    reverse(a.begin() + 1, a.end());
    auto q = Modint(n).inv();
    for(auto& b : a) b *= q;
}


void nttinit(){
    it.resize(23);
    it[0] = Modint(3).pow((MOD-1) / 4);
    rep(i,20) it[i+1] = Modint(3).pow((MOD-1) / (8 << i) * 3 + (MOD-1) / 2);
}

vector<Modint> convolution(vector<Modint> a, vector<Modint> b){
    int n = a.size() + b.size() - 1;
    vector<Modint> res(n);
    int m = 1; while(m < n) m *= 2;
    a.resize(m); b.resize(m);
    ntt(m, a);
    ntt(m, b);
    rep(i,m) a[i] *= b[i];
    intt(m, a);
    rep(i,n) res[i] += a[i];
    return res;
}

vector<Modint> transposed_convolution(vector<Modint> a, vector<Modint> b){
    int n = a.size() - b.size() + 1;
    vector<Modint> res(n);
    int m = 1; while(m < int(a.size())) m *= 2;
    a.resize(m); b.resize(m);
    reverse(b.begin() + 1, b.end());
    ntt(m, a);
    ntt(m, b);
    rep(i,m) a[i] *= b[i];
    intt(m, a);
    rep(i,n) res[i] += a[i];
    return res;
}


void testcase(){
    int N, M; cin >> N >> M;

    vector<Modint> F(M+1), IF(M+1);
    F[0] = 1; for(int i=1; i<=M; i++) F[i] = F[i-1] * i;
    IF[M] = F[M].inv(); for(int  i=M; i>=1; i--) IF[i-1] = IF[i] * i;
    auto comb = [&](int n, int r){ return F[n] * IF[r] * IF[n-r]; };

    vector<int> A(N), B(N);
    rep(i,N) cin >> A[i];
    rep(i,N) cin >> B[i];
    vector<vector<Modint>> Q(N*2), P(N*2);
    rep(i,N){
        vector<Modint> D(A[i]+1);
        rep(b,B[i]) D[b] = comb(A[i], b);
        Q[N+i] = move(D);
    }
    for(int i=N-1; i>=1; i--) Q[i] = convolution(Q[i*2], Q[i*2+1]);
    P[1].resize(M); rep(i,M) P[1][i] = F[i] * F[M-1-i];
    for(int i=2; i<N*2; i++) P[i] = transposed_convolution(P[i/2], Q[i^1]);

    rep(i,N){
        Modint ans = P[N+i][B[i]-1] * comb(A[i]-1, B[i]-1) * A[i];
        cout << ans.x << "\n";
    }
}

int main(){
    cin.tie(0)->sync_with_stdio(0);
    nttinit();
    testcase();
    return 0;
}
accuracy: 1
time_ms: 870
memory_kb: 72676
final_rank: 5

code_snippet: #pragma GCC optimize("O3")
//#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,sse4.1,sse4.2,popcnt,abm,mmx,avx,avx2,fma")
#include <bits/stdc++.h>
#define fi first
#define se second
using namespace std;
//#include <atcoder/all>
//using namespace atcoder;
//#include <bits/extc++.h>
//using namespace __gnu_pbds;
using ll=long long;
using ull=unsigned long long;
using db=long double;
using pii=pair<int,int>;
using pll=pair<ll,ll>;
using pdb=pair<db,db>;
using tii=tuple<int,int,int>;
using tdb=tuple<db,db,db>;
using tll=tuple<ll,ll,ll>;
using ti4=tuple<int,int,int,int>;
using tl4=tuple<ll,ll,ll,ll>;
using td4=tuple<db,db,db,db>;
//using oset=tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update>;
//mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); //shuffle(a+1,a+1+n,rng)
//uniform_int_distribution<> gen(1,100); //gen(rng)
ll modinv(ll a,ll m){
	if(m==1) return 0;
	a%=m;
	if(a<0) a+=m;
	if(a==1) return 1;
	return m-modinv(m,a)*m/a;
}
template <int MOD_> struct modnum{
private:
	int v;
public:
	static const int MOD = MOD_;
	modnum() : v(0) {}
	modnum(ll v_) : v(int(v_ % MOD)) { if (v < 0) v += MOD; }
	explicit operator int () const { return v; }
	friend bool operator == (const modnum& a, const modnum& b) { return a.v == b.v; }
	friend bool operator != (const modnum& a, const modnum& b) { return a.v != b.v; }
	friend bool operator < (const modnum& a, const modnum& b) { return a.v < b.v; }
	friend bool operator <= (const modnum& a, const modnum& b) { return a.v <= b.v; }
	friend bool operator > (const modnum& a, const modnum& b) { return a.v > b.v; }
	friend bool operator >= (const modnum& a, const modnum& b) { return a.v >= b.v; }
	modnum operator ~ () const {
		modnum res;
		res.v = modinv(v, MOD);
		return res;
	}
	modnum& operator += (const modnum& o) {
		v += o.v;
		if (v >= MOD) v -= MOD;
		return *this;
	}
	modnum& operator -= (const modnum& o) {
		v -= o.v;
		if (v < 0) v += MOD;
		return *this;
	}
	modnum& operator *= (const modnum& o) {
		v = int(ll(v) * ll(o.v) % MOD);
		return *this;
	}
	modnum& operator /= (const modnum& o) {
		return *this *= (~o);
	}
	modnum operator-() const { return modnum(-v); }
	modnum& operator++() { return *this += 1; }
	modnum operator++(int){ modnum tmp=*this; ++*this; return tmp; }
	modnum& operator--() { return *this -= 1; }
	modnum operator--(int){ modnum tmp=*this; --*this; return tmp; }
	friend modnum operator + (const modnum& a, const modnum& b) { return modnum(a) += b; }
	friend modnum operator - (const modnum& a, const modnum& b) { return modnum(a) -= b; }
	friend modnum operator * (const modnum& a, const modnum& b) { return modnum(a) *= b; }
	friend modnum operator / (const modnum& a, const modnum& b) { return modnum(a) /= b; }
	friend modnum pow(modnum a, ll p) {
		modnum ans = 1;
		for (; p; p /= 2, a *= a) if (p&1) ans *= a;
		return ans;
	}
	friend ostream& operator<<(std::ostream& os, const modnum& o)
	{
		os << o.v;
		return os;
	}
	friend istream& operator>>(std::istream& is, modnum& o)
	{
		is >> o.v;
		return is;
	}
};
const ll mod=998244353,inf=1e18;
const int N=3e5+5,M=20;
using mi=modnum<mod>;
#define sz(v) ((int)(v).size())
#define all(v) (v).begin(), (v).end()
namespace fft{
	template<typename T>
	void ntt(vector<T> &a, bool inv){
		const int prr = 3; // primitive root
		int n = a.size(), j = 0;
		vector<T> roots(n/2);
		for(int i=1; i<n; i++){
			int bit = (n >> 1);
			while(j >= bit){
				j -= bit;
				bit >>= 1;
			}
			j += bit;
			if(i < j) swap(a[i], a[j]);
		}
		T ang = pow(T(prr), (mod - 1) / n);
		if(inv) ang = T(1) / ang;
		for(int i=0; i<n/2; i++){
			roots[i] = (i ? (roots[i-1] * ang) : T(1));
		}
		for(int i=2; i<=n; i<<=1){
			int step = n / i;
			for(int j=0; j<n; j+=i){
				for(int k=0; k<i/2; k++){
					T u = a[j+k], v = a[j+k+i/2] * roots[step * k];
					a[j+k] = u+v;
					a[j+k+i/2] = u-v;
				}
			}
		}
		if(inv){
			T rev = T(1) / T(n);
			for(int i=0; i<n; i++) a[i] *= rev;
		}
	}
	template<typename T>
	vector<T> multiply_ntt(vector<T> &v, const vector<T> &w){
		vector<T> fv(all(v)), fw(all(w));
		int n = 2;
		while(n < sz(v) + sz(w)) n <<= 1;
		fv.resize(n); fw.resize(n);
		ntt(fv, 0); ntt(fw, 0);
		for(int i=0; i<n; i++) fv[i] *= fw[i];
		ntt(fv, 1);
		vector<T> ret(n);
		for(int i=0; i<n; i++) ret[i] = fv[i];
		ret.resize((int)v.size()+(int)w.size()-1);
		return ret;
	}
}
int n,m,a[N],b[N];
mi fact[N],finv[N],mul=1,ans[N];
vector<mi> T[2*N],F[2*N];
void build(int nd,int l,int r){
	if(l==r){
		T[nd].resize(b[l]);
		for(int i=0;i<b[l];i++) T[nd][i]=finv[i]*finv[a[l]-i];	
		return;
	}
	int m=(l+r)>>1,ln=nd+1,rn=nd+2*(m-l+1);
	build(ln,l,m);
	build(rn,m+1,r);
	T[nd]=fft::multiply_ntt(T[ln],T[rn]);
}
void solve(int nd,int l,int r){
	if(l==r){
		ans[l]=F[nd][b[l]-1]*finv[b[l]-1]*finv[a[l]-b[l]]*mul;
		return;
	}	
	int m=(l+r)>>1,ln=nd+1,rn=nd+2*(m-l+1);
	reverse(T[rn].begin(),T[rn].end());
	F[ln]=fft::multiply_ntt(F[nd],T[rn]);
	F[ln].erase(F[ln].begin(),F[ln].begin()+T[rn].size()-1);
	F[ln].resize(T[ln].size());
	reverse(T[ln].begin(),T[ln].end());
	F[rn]=fft::multiply_ntt(F[nd],T[ln]);
	F[rn].erase(F[rn].begin(),F[rn].begin()+T[ln].size()-1);
	F[rn].resize(T[rn].size());
	solve(ln,l,m);
	solve(rn,m+1,r);
}
int main(){
	ios::sync_with_stdio(false); cin.tie(0);
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=n;i++) cin>>b[i];
	fact[0]=finv[0]=1;
	for(int i=1;i<=m;i++){
		fact[i]=fact[i-1]*i;
		finv[i]=~fact[i];
	}
	for(int i=1;i<=n;i++) mul*=fact[a[i]];
	build(1,1,n);
	F[1]=T[1];
	for(int i=0;i<(int)F[1].size();i++) F[1][i]=fact[i]*fact[m-1-i];
	solve(1,1,n);
	for(int i=1;i<=n;i++) cout<<ans[i]<<"\n";
	return 0;
}
accuracy: 1
time_ms: 2330
memory_kb: 101376
final_rank: 7

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=2167167167167167167;
const int INF=2100000000;
const int mod=998244353;
#define rep(i,a,b) for (ll i=a;i<b;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";}
template<class T> T min(vector<T> &a){assert(!a.empty());T ans=a[0];for(auto &x:a) chmin(ans,x);return ans;}
template<class T> T max(vector<T> &a){assert(!a.empty());T ans=a[0];for(auto &x:a) chmax(ans,x);return ans;}
template<class T> T sum(vector<T> &a){assert(!a.empty());T ans=a[0]-a[0];for(auto &x:a) ans+=x;return ans;}

namespace atcoder {

namespace internal {

// @param n `0 <= n`
// @return minimum non-negative `x` s.t. `n <= 2**x`
int ceil_pow2(int n) {
    int x = 0;
    while ((1U << x) < (unsigned int)(n)) x++;
    return x;
}

// @param n `1 <= n`
// @return minimum non-negative `x` s.t. `(n & (1 << x)) != 0`
int bsf(unsigned int n) {
#ifdef _MSC_VER
    unsigned long index;
    _BitScanForward(&index, n);
    return index;
#else
    return __builtin_ctz(n);
#endif
}

}  // namespace internal

namespace internal {

// @param m `1 <= m`
// @return x mod m
constexpr long long safe_mod(long long x, long long m) {
    x %= m;
    if (x < 0) x += m;
    return x;
}

// Fast modular multiplication by barrett reduction
// Reference: https://en.wikipedia.org/wiki/Barrett_reduction
// NOTE: reconsider after Ice Lake
struct barrett {
    unsigned int _m;
    unsigned long long im;

    // @param m `1 <= m < 2^31`
    barrett(unsigned int m) : _m(m), im((unsigned long long)(-1) / m + 1) {}

    // @return m
    unsigned int umod() const { return _m; }

    // @param a `0 <= a < m`
    // @param b `0 <= b < m`
    // @return `a * b % m`
    unsigned int mul(unsigned int a, unsigned int b) const {
        // [1] m = 1
        // a = b = im = 0, so okay

        // [2] m >= 2
        // im = ceil(2^64 / m)
        // -> im * m = 2^64 + r (0 <= r < m)
        // let z = a*b = c*m + d (0 <= c, d < m)
        // a*b * im = (c*m + d) * im = c*(im*m) + d*im = c*2^64 + c*r + d*im
        // c*r + d*im < m * m + m * im < m * m + 2^64 + m <= 2^64 + m * (m + 1) < 2^64 * 2
        // ((ab * im) >> 64) == c or c + 1
        unsigned long long z = a;
        z *= b;
#ifdef _MSC_VER
        unsigned long long x;
        _umul128(z, im, &x);
#else
        unsigned long long x =
            (unsigned long long)(((unsigned __int128)(z)*im) >> 64);
#endif
        unsigned int v = (unsigned int)(z - x * _m);
        if (_m <= v) v += _m;
        return v;
    }
};

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

// Reference:
// M. Forisek and J. Jancina,
// Fast Primality Testing for Integers That Fit into a Machine Word
// @param n `0 <= n`
constexpr bool is_prime_constexpr(int n) {
    if (n <= 1) return false;
    if (n == 2 || n == 7 || n == 61) return true;
    if (n % 2 == 0) return false;
    long long d = n - 1;
    while (d % 2 == 0) d /= 2;
    constexpr long long bases[3] = {2, 7, 61};
    for (long long a : bases) {
        long long t = d;
        long long y = pow_mod_constexpr(a, t, n);
        while (t != n - 1 && y != 1 && y != n - 1) {
            y = y * y % n;
            t <<= 1;
        }
        if (y != n - 1 && t % 2 == 0) {
            return false;
        }
    }
    return true;
}
template <int n> constexpr bool is_prime = is_prime_constexpr(n);

// @param b `1 <= b`
// @return pair(g, x) s.t. g = gcd(a, b), xa = g (mod b), 0 <= x < b/g
constexpr std::pair<long long, long long> inv_gcd(long long a, long long b) {
    a = safe_mod(a, b);
    if (a == 0) return {b, 0};

    // Contracts:
    // [1] s - m0 * a = 0 (mod b)
    // [2] t - m1 * a = 0 (mod b)
    // [3] s * |m1| + t * |m0| <= b
    long long s = b, t = a;
    long long m0 = 0, m1 = 1;

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

        // [3]:
        // (s - t * u) * |m1| + t * |m0 - m1 * u|
        // <= s * |m1| - t * u * |m1| + t * (|m0| + |m1| * u)
        // = s * |m1| + t * |m0| <= b

        auto tmp = s;
        s = t;
        t = tmp;
        tmp = m0;
        m0 = m1;
        m1 = tmp;
    }
    // by [3]: |m0| <= b/g
    // by g != b: |m0| < b/g
    if (m0 < 0) m0 += b / s;
    return {s, m0};
}

// Compile time primitive root
// @param m must be prime
// @return primitive root (and minimum in now)
constexpr int primitive_root_constexpr(int m) {
    if (m == 2) return 1;
    if (m == 167772161) return 3;
    if (m == 469762049) return 3;
    if (m == 754974721) return 11;
    if (m == 998244353) return 3;
    int divs[20] = {};
    divs[0] = 2;
    int cnt = 1;
    int x = (m - 1) / 2;
    while (x % 2 == 0) x /= 2;
    for (int i = 3; (long long)(i)*i <= x; i += 2) {
        if (x % i == 0) {
            divs[cnt++] = i;
            while (x % i == 0) {
                x /= i;
            }
        }
    }
    if (x > 1) {
        divs[cnt++] = x;
    }
    for (int g = 2;; g++) {
        bool ok = true;
        for (int i = 0; i < cnt; i++) {
            if (pow_mod_constexpr(g, (m - 1) / divs[i], m) == 1) {
                ok = false;
                break;
            }
        }
        if (ok) return g;
    }
}
template <int m> constexpr int primitive_root = primitive_root_constexpr(m);

}  // namespace internal

namespace internal {

#ifndef _MSC_VER
template <class T>
using is_signed_int128 =
    typename std::conditional<std::is_same<T, __int128_t>::value ||
                                  std::is_same<T, __int128>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using is_unsigned_int128 =
    typename std::conditional<std::is_same<T, __uint128_t>::value ||
                                  std::is_same<T, unsigned __int128>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using make_unsigned_int128 =
    typename std::conditional<std::is_same<T, __int128_t>::value,
                              __uint128_t,
                              unsigned __int128>;

template <class T>
using is_integral = typename std::conditional<std::is_integral<T>::value ||
                                                  is_signed_int128<T>::value ||
                                                  is_unsigned_int128<T>::value,
                                              std::true_type,
                                              std::false_type>::type;

template <class T>
using is_signed_int = typename std::conditional<(is_integral<T>::value &&
                                                 std::is_signed<T>::value) ||
                                                    is_signed_int128<T>::value,
                                                std::true_type,
                                                std::false_type>::type;

template <class T>
using is_unsigned_int =
    typename std::conditional<(is_integral<T>::value &&
                               std::is_unsigned<T>::value) ||
                                  is_unsigned_int128<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<
    is_signed_int128<T>::value,
    make_unsigned_int128<T>,
    typename std::conditional<std::is_signed<T>::value,
                              std::make_unsigned<T>,
                              std::common_type<T>>::type>::type;

#else

template <class T> using is_integral = typename std::is_integral<T>;

template <class T>
using is_signed_int =
    typename std::conditional<is_integral<T>::value && std::is_signed<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using is_unsigned_int =
    typename std::conditional<is_integral<T>::value &&
                                  std::is_unsigned<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<is_signed_int<T>::value,
                                              std::make_unsigned<T>,
                                              std::common_type<T>>::type;

#endif

template <class T>
using is_signed_int_t = std::enable_if_t<is_signed_int<T>::value>;

template <class T>
using is_unsigned_int_t = std::enable_if_t<is_unsigned_int<T>::value>;

template <class T> using to_unsigned_t = typename to_unsigned<T>::type;

}  // namespace internal



namespace internal {

struct modint_base {};
struct static_modint_base : modint_base {};

template <class T> using is_modint = std::is_base_of<modint_base, T>;
template <class T> using is_modint_t = std::enable_if_t<is_modint<T>::value>;

}  // namespace internal

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

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

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

    unsigned int val() const { return _v; }

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

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

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

    mint pow(long long n) const {
        assert(0 <= n);
        mint x = *this, r = 1;
        while (n) {
            if (n & 1) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    mint inv() const {
        if (prime) {
            assert(_v);
            return pow(umod() - 2);
        } else {
            auto eg = internal::inv_gcd(_v, m);
            assert(eg.first == 1);
            return eg.second;
        }
    }

    friend mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    friend mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    friend mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    friend mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    friend bool operator==(const mint& lhs, const mint& rhs) {
        return lhs._v == rhs._v;
    }
    friend bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs._v != rhs._v;
    }

  private:
    unsigned int _v;
    static constexpr unsigned int umod() { return m; }
    static constexpr bool prime = internal::is_prime<m>;
};

template <int id> struct dynamic_modint : internal::modint_base {
    using mint = dynamic_modint;

  public:
    static int mod() { return (int)(bt.umod()); }
    static void set_mod(int m) {
        assert(1 <= m);
        bt = internal::barrett(m);
    }
    static mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }

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

    unsigned int val() const { return _v; }

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

    mint& operator+=(const mint& rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator-=(const mint& rhs) {
        _v += mod() - rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator*=(const mint& rhs) {
        _v = bt.mul(_v, rhs._v);
        return *this;
    }
    mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }

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

    mint pow(long long n) const {
        assert(0 <= n);
        mint x = *this, r = 1;
        while (n) {
            if (n & 1) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    mint inv() const {
        auto eg = internal::inv_gcd(_v, mod());
        assert(eg.first == 1);
        return eg.second;
    }

    friend mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    friend mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    friend mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    friend mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    friend bool operator==(const mint& lhs, const mint& rhs) {
        return lhs._v == rhs._v;
    }
    friend bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs._v != rhs._v;
    }

  private:
    unsigned int _v;
    static internal::barrett bt;
    static unsigned int umod() { return bt.umod(); }
};
template <int id> internal::barrett dynamic_modint<id>::bt = 998244353;

using modint998244353 = static_modint<998244353>;
using modint1000000007 = static_modint<1000000007>;
using modint = dynamic_modint<-1>;

namespace internal {

template <class T>
using is_static_modint = std::is_base_of<internal::static_modint_base, T>;

template <class T>
using is_static_modint_t = std::enable_if_t<is_static_modint<T>::value>;

template <class> struct is_dynamic_modint : public std::false_type {};
template <int id>
struct is_dynamic_modint<dynamic_modint<id>> : public std::true_type {};

template <class T>
using is_dynamic_modint_t = std::enable_if_t<is_dynamic_modint<T>::value>;

}  // namespace internal

namespace internal {

template <class mint, internal::is_static_modint_t<mint>* = nullptr>
void butterfly(std::vector<mint>& a) {
    static constexpr int g = internal::primitive_root<mint::mod()>;
    int n = int(a.size());
    int h = internal::ceil_pow2(n);

    static bool first = true;
    static mint sum_e[30];  // sum_e[i] = ies[0] * ... * ies[i - 1] * es[i]
    if (first) {
        first = false;
        mint es[30], ies[30];  // es[i]^(2^(2+i)) == 1
        int cnt2 = bsf(mint::mod() - 1);
        mint e = mint(g).pow((mint::mod() - 1) >> cnt2), ie = e.inv();
        for (int i = cnt2; i >= 2; i--) {
            // e^(2^i) == 1
            es[i - 2] = e;
            ies[i - 2] = ie;
            e *= e;
            ie *= ie;
        }
        mint now = 1;
        for (int i = 0; i <= cnt2 - 2; i++) {
            sum_e[i] = es[i] * now;
            now *= ies[i];
        }
    }
    for (int ph = 1; ph <= h; ph++) {
        int w = 1 << (ph - 1), p = 1 << (h - ph);
        mint now = 1;
        for (int s = 0; s < w; s++) {
            int offset = s << (h - ph + 1);
            for (int i = 0; i < p; i++) {
                auto l = a[i + offset];
                auto r = a[i + offset + p] * now;
                a[i + offset] = l + r;
                a[i + offset + p] = l - r;
            }
            now *= sum_e[bsf(~(unsigned int)(s))];
        }
    }
}

template <class mint, internal::is_static_modint_t<mint>* = nullptr>
void butterfly_inv(std::vector<mint>& a) {
    static constexpr int g = internal::primitive_root<mint::mod()>;
    int n = int(a.size());
    int h = internal::ceil_pow2(n);

    static bool first = true;
    static mint sum_ie[30];  // sum_ie[i] = es[0] * ... * es[i - 1] * ies[i]
    if (first) {
        first = false;
        mint es[30], ies[30];  // es[i]^(2^(2+i)) == 1
        int cnt2 = bsf(mint::mod() - 1);
        mint e = mint(g).pow((mint::mod() - 1) >> cnt2), ie = e.inv();
        for (int i = cnt2; i >= 2; i--) {
            // e^(2^i) == 1
            es[i - 2] = e;
            ies[i - 2] = ie;
            e *= e;
            ie *= ie;
        }
        mint now = 1;
        for (int i = 0; i <= cnt2 - 2; i++) {
            sum_ie[i] = ies[i] * now;
            now *= es[i];
        }
    }

    for (int ph = h; ph >= 1; ph--) {
        int w = 1 << (ph - 1), p = 1 << (h - ph);
        mint inow = 1;
        for (int s = 0; s < w; s++) {
            int offset = s << (h - ph + 1);
            for (int i = 0; i < p; i++) {
                auto l = a[i + offset];
                auto r = a[i + offset + p];
                a[i + offset] = l + r;
                a[i + offset + p] =
                    (unsigned long long)(mint::mod() + l.val() - r.val()) *
                    inow.val();
            }
            inow *= sum_ie[bsf(~(unsigned int)(s))];
        }
    }
}

}  // namespace internal

template <class mint, internal::is_static_modint_t<mint>* = nullptr>
std::vector<mint> convolution(std::vector<mint> a, std::vector<mint> b) {
    int n = int(a.size()), m = int(b.size());
    if (!n || !m) return {};
    if (std::min(n, m) <= 60) {
        if (n < m) {
            std::swap(n, m);
            std::swap(a, b);
        }
        std::vector<mint> ans(n + m - 1);
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                ans[i + j] += a[i] * b[j];
            }
        }
        return ans;
    }
    int z = 1 << internal::ceil_pow2(n + m - 1);
    a.resize(z);
    internal::butterfly(a);
    b.resize(z);
    internal::butterfly(b);
    for (int i = 0; i < z; i++) {
        a[i] *= b[i];
    }
    internal::butterfly_inv(a);
    a.resize(n + m - 1);
    mint iz = mint(z).inv();
    for (int i = 0; i < n + m - 1; i++) a[i] *= iz;
    return a;
}

template <unsigned int mod = 998244353,
          class T,
          std::enable_if_t<internal::is_integral<T>::value>* = nullptr>
std::vector<T> convolution(const std::vector<T>& a, const std::vector<T>& b) {
    int n = int(a.size()), m = int(b.size());
    if (!n || !m) return {};

    using mint = static_modint<mod>;
    std::vector<mint> a2(n), b2(m);
    for (int i = 0; i < n; i++) {
        a2[i] = mint(a[i]);
    }
    for (int i = 0; i < m; i++) {
        b2[i] = mint(b[i]);
    }
    auto c2 = convolution(move(a2), move(b2));
    std::vector<T> c(n + m - 1);
    for (int i = 0; i < n + m - 1; i++) {
        c[i] = c2[i].val();
    }
    return c;
}

std::vector<long long> convolution_ll(const std::vector<long long>& a,
                                      const std::vector<long long>& b) {
    int n = int(a.size()), m = int(b.size());
    if (!n || !m) return {};

    static constexpr unsigned long long MOD1 = 754974721;  // 2^24
    static constexpr unsigned long long MOD2 = 167772161;  // 2^25
    static constexpr unsigned long long MOD3 = 469762049;  // 2^26
    static constexpr unsigned long long M2M3 = MOD2 * MOD3;
    static constexpr unsigned long long M1M3 = MOD1 * MOD3;
    static constexpr unsigned long long M1M2 = MOD1 * MOD2;
    static constexpr unsigned long long M1M2M3 = MOD1 * MOD2 * MOD3;

    static constexpr unsigned long long i1 =
        internal::inv_gcd(MOD2 * MOD3, MOD1).second;
    static constexpr unsigned long long i2 =
        internal::inv_gcd(MOD1 * MOD3, MOD2).second;
    static constexpr unsigned long long i3 =
        internal::inv_gcd(MOD1 * MOD2, MOD3).second;

    auto c1 = convolution<MOD1>(a, b);
    auto c2 = convolution<MOD2>(a, b);
    auto c3 = convolution<MOD3>(a, b);

    std::vector<long long> c(n + m - 1);
    for (int i = 0; i < n + m - 1; i++) {
        unsigned long long x = 0;
        x += (c1[i] * i1) % MOD1 * M2M3;
        x += (c2[i] * i2) % MOD2 * M1M3;
        x += (c3[i] * i3) % MOD3 * M1M2;
        // B = 2^63, -B <= x, r(real value) < B
        // (x, x - M, x - 2M, or x - 3M) = r (mod 2B)
        // r = c1[i] (mod MOD1)
        // focus on MOD1
        // r = x, x - M', x - 2M', x - 3M' (M' = M % 2^64) (mod 2B)
        // r = x,
        //     x - M' + (0 or 2B),
        //     x - 2M' + (0, 2B or 4B),
        //     x - 3M' + (0, 2B, 4B or 6B) (without mod!)
        // (r - x) = 0, (0)
        //           - M' + (0 or 2B), (1)
        //           -2M' + (0 or 2B or 4B), (2)
        //           -3M' + (0 or 2B or 4B or 6B) (3) (mod MOD1)
        // we checked that
        //   ((1) mod MOD1) mod 5 = 2
        //   ((2) mod MOD1) mod 5 = 3
        //   ((3) mod MOD1) mod 5 = 4
        long long diff =
            c1[i] - internal::safe_mod((long long)(x), (long long)(MOD1));
        if (diff < 0) diff += MOD1;
        static constexpr unsigned long long offset[5] = {
            0, 0, M1M2M3, 2 * M1M2M3, 3 * M1M2M3};
        x -= offset[diff % 5];
        c[i] = x;
    }

    return c;
}

}  // namespace atcoder
using namespace atcoder;

namespace po167{
struct combination{
	int upper;
	long long MOD;
	std::vector<long long> fact;
	std::vector<long long> rev;
	std::vector<long long> fact_rev;
	combination(int max,long long mod):upper(max),MOD(mod),fact(max+1),rev(max+1),fact_rev(max+1){
		for(long long i=0;i<=max;i++){
			if(i<2){
				fact[i]=1;
				fact_rev[i]=1;
				rev[i]=1;
				continue;
			}
			fact[i]=(fact[i-1]*i)%mod;
			rev[i]=mod-((mod/i)*rev[mod%i])%mod;
			fact_rev[i]=(fact_rev[i-1]*rev[i])%mod;
		}
	}
	long long Comb(int x,int y){
		assert(upper>=x);
		if (x<y||y<0||x<0) return 0;
		return (((fact_rev[y]*fact_rev[x-y])%MOD)*fact[x])%MOD;
	}
	long long P(int x,int y){
		assert(upper>=x);
		if (x<y||y<0||x<0) return 0;
		return (fact_rev[x-y]*fact[x])%MOD;
	}
};
}
using po167::combination;



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

void solve(){
	ll N,M;
	cin>>N>>M;
	combination table(M,mod);
	vector<ll> A(N),B(N);
	rep(i,0,N) cin>>A[i];
	rep(i,0,N) cin>>B[i];
	int L=1;
	while(L<N) L*=2;
	vector<vector<ll>> base(L*2,{1});
	vector<vector<ll>> dp(L*2);
	vector<int> digi(L*2);
	rep(i,0,N){
		vector<ll> tmp(B[i]);
		rep(j,0,B[i]) tmp[j]=table.Comb(A[i],j);
		base[i+L]=tmp;
	}
	for(int i=L-1;i>0;i--) base[i]=convolution(base[i*2],base[i*2+1]);
	dp[1].resize(base[1].size());
	rep(i,0,(int)base[1].size()){
		int v=M-1-((int)base[1].size()-1-i);
		dp[1][i]=(table.fact[v]*table.fact[M-1-v])%mod;
	}
	rep(i,2,L*2){
		auto tmp=convolution(dp[i/2],base[i^1]);
		dp[i].resize(base[i].size());
		rep(j,0,(int)base[i].size()) dp[i][j]=tmp[j+(int)(base[i^1].size())-1];
	}
	rep(i,0,N){
		cout<<(A[i]*((dp[i+L][0]*table.Comb(A[i]-1,B[i]-1))%mod))%mod<<"\n";
	}
}
accuracy: 1
time_ms: 1490
memory_kb: 76812
final_rank: 6

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
using uint = unsigned int;
using ull = unsigned long long;
#define rep(i,n) for(int i=0;i<int(n);i++)
#define rep1(i,n) for(int i=1;i<=int(n);i++)
#define per(i,n) for(int i=int(n)-1;i>=0;i--)
#define per1(i,n) for(int i=int(n);i>0;i--)
#define all(c) c.begin(),c.end()
#define si(x) int(x.size())
#define pb push_back
#define eb emplace_back
#define fs first
#define sc second
template<class T> using V = vector<T>;
template<class T> using VV = vector<vector<T>>;
template<class T,class U> bool chmax(T& x, U y){
	if(x<y){ x=y; return true; }
	return false;
}
template<class T,class U> bool chmin(T& x, U y){
	if(y<x){ x=y; return true; }
	return false;
}
template<class T> void mkuni(V<T>& v){sort(all(v));v.erase(unique(all(v)),v.end());}
template<class T> int lwb(const V<T>& v, const T& a){return lower_bound(all(v),a) - v.begin();}
template<class T>
V<T> Vec(size_t a) {
    return V<T>(a);
}
template<class T, class... Ts>
auto Vec(size_t a, Ts... ts) {
  return V<decltype(Vec<T>(ts...))>(a, Vec<T>(ts...));
}
template<class S,class T> ostream& operator<<(ostream& o,const pair<S,T> &p){
	return o<<"("<<p.fs<<","<<p.sc<<")";
}
template<class T> ostream& operator<<(ostream& o,const vector<T> &vc){
	o<<"{";
	for(const T& v:vc) o<<v<<",";
	o<<"}";
	return o;
}
constexpr ll TEN(int n) { return (n == 0) ? 1 : 10 * TEN(n-1); }

#ifdef LOCAL
#define show(x) cerr << "LINE" << __LINE__ << " : " << #x << " = " << (x) << endl
void dmpr(ostream& os){os<<endl;}
template<class T,class... Args>
void dmpr(ostream&os,const T&t,const Args&... args){
	os<<t<<" ~ ";
	dmpr(os,args...);
}
#define shows(...) cerr << "LINE" << __LINE__ << " : ";dmpr(cerr,##__VA_ARGS__)
#define dump(x) cerr << "LINE" << __LINE__ << " : " << #x << " = {";  \
	for(auto v: x) cerr << v << ","; cerr << "}" << endl;
#else
#define show(x) void(0)
#define dump(x) void(0)
#define shows(...) void(0)
#endif

template<class D> D divFloor(D a, D b){
	return a / b - (((a ^ b) < 0 && a % b != 0) ? 1 : 0);
}
template<class D> D divCeil(D a, D b) {
	return a / b + (((a ^ b) > 0 && a % b != 0) ? 1 : 0);
}

template<unsigned int mod_>
struct ModInt{
	using uint = unsigned int;
	using ll = long long;
	using ull = unsigned long long;

	constexpr static uint mod = mod_;

	uint v;
	ModInt():v(0){}
	ModInt(ll _v):v(normS(_v%mod+mod)){}
	explicit operator bool() const {return v!=0;}
	static uint normS(const uint &x){return (x<mod)?x:x-mod;}		// [0 , 2*mod-1] -> [0 , mod-1]
	static ModInt make(const uint &x){ModInt m; m.v=x; return m;}
	ModInt operator+(const ModInt& b) const { return make(normS(v+b.v));}
	ModInt operator-(const ModInt& b) const { return make(normS(v+mod-b.v));}
	ModInt operator-() const { return make(normS(mod-v)); }
	ModInt operator*(const ModInt& b) const { return make((ull)v*b.v%mod);}
	ModInt operator/(const ModInt& b) const { return *this*b.inv();}
	ModInt& operator+=(const ModInt& b){ return *this=*this+b;}
	ModInt& operator-=(const ModInt& b){ return *this=*this-b;}
	ModInt& operator*=(const ModInt& b){ return *this=*this*b;}
	ModInt& operator/=(const ModInt& b){ return *this=*this/b;}
	ModInt& operator++(int){ return *this=*this+1;}
	ModInt& operator--(int){ return *this=*this-1;}
	template<class T> friend ModInt operator+(T a, const ModInt& b){ return (ModInt(a) += b);}
	template<class T> friend ModInt operator-(T a, const ModInt& b){ return (ModInt(a) -= b);}
	template<class T> friend ModInt operator*(T a, const ModInt& b){ return (ModInt(a) *= b);}
	template<class T> friend ModInt operator/(T a, const ModInt& b){ return (ModInt(a) /= b);}
	ModInt pow(ll p) const {
		if(p<0) return inv().pow(-p);
		ModInt a = 1;
		ModInt x = *this;
		while(p){
			if(p&1) a *= x;
			x *= x;
			p >>= 1;
		}
		return a;
	}
	ModInt inv() const {		// should be prime
		return pow(mod-2);
	}
	// ll extgcd(ll a,ll b,ll &x,ll &y) const{
	// 	ll p[]={a,1,0},q[]={b,0,1};
	// 	while(*q){
	// 		ll t=*p/ *q;
	// 		rep(i,3) swap(p[i]-=t*q[i],q[i]);
	// 	}
	// 	if(p[0]<0) rep(i,3) p[i]=-p[i];
	// 	x=p[1],y=p[2];
	// 	return p[0];
	// }
	// ModInt inv() const {
	// 	ll x,y;
	// 	extgcd(v,mod,x,y);
	// 	return make(normS(x+mod));
	// }

	bool operator==(const ModInt& b) const { return v==b.v;}
	bool operator!=(const ModInt& b) const { return v!=b.v;}
	bool operator<(const ModInt& b) const { return v<b.v;}
	friend istream& operator>>(istream &o,ModInt& x){
		ll tmp;
		o>>tmp;
		x=ModInt(tmp);
		return o;
	}
	friend ostream& operator<<(ostream &o,const ModInt& x){ return o<<x.v;}
};
using mint = ModInt<998244353>;
//using mint = ModInt<1000000007>;

V<mint> fact,ifact,invs;
mint Choose(int a,int b){
	if(b<0 || a<b) return 0;
	return fact[a] * ifact[b] * ifact[a-b];
}
void InitFact(int N){	//[0,N]
	N++;
	fact.resize(N);
	ifact.resize(N);
	invs.resize(N);
	fact[0] = 1;
	rep1(i,N-1) fact[i] = fact[i-1] * i;
	ifact[N-1] = fact[N-1].inv();
	for(int i=N-2;i>=0;i--) ifact[i] = ifact[i+1] * (i+1);
	rep1(i,N-1) invs[i] = fact[i-1] * ifact[i];
}

// inplace_fmt (without bit rearranging)
// fft:
// 		a[rev(i)] <- \sum_j \zeta^{ij} a[j]
// invfft:
//		a[i] <- (1/n) \sum_j \zeta^{-ij} a[rev(j)]
// These two are inversions.


// !!! CHANGE IF MOD is unusual !!!
const int ORDER_2_MOD_MINUS_1 = 23;	// ord_2 (mod-1)
const mint PRIMITIVE_ROOT = 3; // primitive root of (Z/pZ)*

void fft(V<mint>& a){
	static constexpr uint mod = mint::mod;
	static constexpr uint mod2 = mod + mod;
	static const int H = ORDER_2_MOD_MINUS_1;
	static const mint root = PRIMITIVE_ROOT;
	static mint magic[H-1];

	int n = si(a);
	assert(!(n & (n-1))); assert(n >= 1); assert(n <= 1<<H);	// n should be power of 2

	if(!magic[0]){		// precalc
		rep(i,H-1){
			mint w = -root.pow(((mod-1)>>(i+2))*3);
			magic[i] = w;
		}
	}
	int m = n;
	if(m >>= 1){
		rep(i,m){
			uint v = a[i+m].v;					// < M
			a[i+m].v = a[i].v + mod - v;		// < 2M
			a[i].v += v;						// < 2M
		}
	}
	if(m >>= 1){
		mint p = 1;
		for(int h=0,s=0; s<n; s += m*2){
			for(int i=s;i<s+m;i++){
				uint v = (a[i+m] * p).v;		// < M
				a[i+m].v = a[i].v + mod - v;	// < 3M
				a[i].v += v;					// < 3M
			}
			p *= magic[__builtin_ctz(++h)];
		}
	}
	while(m){
		if(m >>= 1){
			mint p = 1;
			for(int h=0,s=0; s<n; s += m*2){
				for(int i=s;i<s+m;i++){
					uint v = (a[i+m] * p).v;		// < M
					a[i+m].v = a[i].v + mod - v;	// < 4M
					a[i].v += v;					// < 4M
				}
				p *= magic[__builtin_ctz(++h)];
			}
		}
		if(m >>= 1){
			mint p = 1;
			for(int h=0,s=0; s<n; s += m*2){
				for(int i=s;i<s+m;i++){
					uint v = (a[i+m] * p).v;								// < M
					a[i].v = (a[i].v >= mod2) ? a[i].v - mod2 : a[i].v;	// < 2M
					a[i+m].v = a[i].v + mod - v;							// < 3M
					a[i].v += v;											// < 3M
				}
				p *= magic[__builtin_ctz(++h)];
			}
		}
	}
	rep(i,n){
		a[i].v = (a[i].v >= mod2) ? a[i].v - mod2 : a[i].v;		// < 2M
		a[i].v = (a[i].v >= mod) ? a[i].v - mod : a[i].v;		// < M
	}
	// finally < mod !!
}
void invfft(V<mint>& a){
	static constexpr uint mod = mint::mod;
	static constexpr uint mod2 = mod + mod;
	static const int H = ORDER_2_MOD_MINUS_1;
	static const mint root = PRIMITIVE_ROOT;
	static mint magic[H-1];

	int n = si(a);
	assert(!(n & (n-1))); assert(n >= 1); assert(n <= 1<<H);	// n should be power of 2

	if(!magic[0]){		// precalc
		rep(i,H-1){
			mint w = -root.pow(((mod-1)>>(i+2))*3);
			magic[i] = w.inv();
		}
	}
	int m = 1;
	if(m < n>>1){
		mint p = 1;
		for(int h=0,s=0; s<n; s += m*2){
			for(int i=s;i<s+m;i++){
				ull x = a[i].v + mod - a[i+m].v;	// < 2M
				a[i].v += a[i+m].v;					// < 2M
				a[i+m].v = (p.v * x) % mod;			// < M
			}
			p *= magic[__builtin_ctz(++h)];
		}
		m <<= 1;
	}
	for(;m < n>>1; m <<= 1){
		mint p = 1;
		for(int h=0,s=0; s<n; s+= m*2){
			for(int i=s;i<s+(m>>1);i++){
				ull x = a[i].v + mod2 - a[i+m].v;	// < 4M
				a[i].v += a[i+m].v;					// < 4M
				a[i].v = (a[i].v >= mod2) ? a[i].v - mod2 : a[i].v;	// < 2M
				a[i+m].v = (p.v * x) % mod;		// < M
			}
			for(int i=s+(m>>1); i<s+m; i++){
				ull x = a[i].v + mod - a[i+m].v;	// < 2M
				a[i].v += a[i+m].v;	// < 2M
				a[i+m].v = (p.v * x) % mod;	// < M
			}
			p *= magic[__builtin_ctz(++h)];
		}
	}
	if(m < n){
		rep(i,m){
			uint x = a[i].v + mod2 - a[i+m].v;	// < 4M
			a[i].v += a[i+m].v;	// < 4M
			a[i+m].v = x;	// < 4M
		}
	}
	const mint in = mint(n).inv();
	rep(i,n) a[i] *= in;	// < M
	// finally < mod !!
}

// A,B = 500000 -> 70ms
// verify https://judge.yosupo.jp/submission/44937
V<mint> multiply(V<mint> a, V<mint> b) {
	int A = si(a), B = si(b);
	if (!A || !B) return {};
	int n = A+B-1;
	int s = 1; while(s<n) s*=2;
	if(a == b){			// # of fft call : 3 -> 2
		a.resize(s); fft(a);
		rep(i,s) a[i] *= a[i];
	}else{
		a.resize(s); fft(a);
		b.resize(s); fft(b);
		rep(i,s) a[i] *= b[i];
	}
	invfft(a); a.resize(n);
	return a;
}

/*
	係数アクセス
		f[i] でいいが、 配列外参照する可能性があるなら at/set
	
*/

template<class mint>
struct Poly: public V<mint>{
	using vector<mint>::vector;
	Poly() {}
	explicit Poly(int n) : V<mint>(n){}		// poly<mint> a; a = 2; shouldn't be [0,0]
	Poly(int n, mint c) : V<mint>(n,c){}
	Poly(const V<mint>& a) : V<mint>(a){}
	Poly(initializer_list<mint> li) : V<mint>(li){}

	int size() const { return V<mint>::size(); }
	mint at(int i) const {
		return i<size() ? (*this)[i] : 0;
	}
	void set(int i, mint x){
		if(i>=size() && !x) return;
		while(i>=size()) this->pb(0);
		(*this)[i] = x;
		return;
	}
	mint operator()(mint x) const {		// eval
		mint res = 0;
		int n = size();
		mint a = 1;
		rep(i,n){
			res += a * (*this)[i];
			a *= x;
		}
		return res;
	}
	Poly low(int n) const {		// ignore x^n (take first n), but not empty
		return Poly(this->begin(), this->begin()+min(max(n,1),size()));
	}
	Poly rev() const {
		return Poly(this->rbegin(), this->rend());
	}
	friend ostream& operator<<(ostream &o,const Poly& f){
		o << "[";
		rep(i,f.size()){
			o << f[i];
			if(i != f.size()-1) o << ",";
		}
		o << "]";
		return o;
	}

	Poly operator-() const {
		Poly res = *this;
		for(auto& v: res) v = -v;
		return res;
	}
	Poly& operator+=(const mint& c){
		(*this)[0] += c;
		return *this;
	}
	Poly& operator-=(const mint& c){
		(*this)[0] -= c;
		return *this;
	}
	Poly& operator*=(const mint& c){
		for(auto& v: *this) v *= c;
		return *this;
	}
	Poly& operator/=(const mint& c){
		return *this *= mint(1)/mint(c);
	}
	Poly& operator+=(const Poly& r){
		if(size() < r.size()) this->resize(r.size(),0);
		rep(i,r.size()) (*this)[i] += r[i];
		return *this;
	}
	Poly& operator-=(const Poly& r){
		if(size() < r.size()) this->resize(r.size(),0);
		rep(i,r.size()) (*this)[i] -= r[i];
		return *this;
	}
	Poly& operator*=(const Poly& r){
		return *this = multiply(*this,r);
	}

	// 何回も同じrで割り算するなら毎回rinvを計算するのは無駄なので、呼び出し側で一回計算した後直接こっちを呼ぶと良い
	// 取るべきinvの長さに注意
	// 例えば mod r で色々計算したい時は、基本的に deg(r) * 2 長さの多項式を r で割ることになる
	// とはいえいったん rinv を長く計算したらより短い場合はprefix見るだけだし、 rinv としてムダに長いものを渡しても問題ないので
	// 割られる多項式として最大の次数を取ればよい

	Poly quotient(const Poly& r, const Poly& rinv){
		int m = r.size(); assert(r[m-1].v);
		int n = size();
		int s = n-m+1;
		if(s <= 0) return {0};
		return (rev().low(s)*rinv.low(s)).low(s).rev();
	}
	Poly& operator/=(const Poly& r){
		return *this = quotient(r,r.rev().inv(max(size()-r.size(),0)+1));
	}
	Poly& operator%=(const Poly& r){
		*this -= *this/r * r;
		return *this = low(r.size()-1);
	}

	Poly operator+(const mint& c) const {return Poly(*this) += c; }
	Poly operator-(const mint& c) const {return Poly(*this) -= c; }
	Poly operator*(const mint& c) const {return Poly(*this) *= c; }
	Poly operator/(const mint& c) const {return Poly(*this) /= c; }
	Poly operator+(const Poly& r) const {return Poly(*this) += r; }
	Poly operator-(const Poly& r) const {return Poly(*this) -= r; }
	Poly operator*(const Poly& r) const {return Poly(*this) *= r; }
	Poly operator/(const Poly& r) const {return Poly(*this) /= r; }
	Poly operator%(const Poly& r) const {return Poly(*this) %= r; }

	Poly diff() const {
		Poly g(max(size()-1,0));
		rep(i,g.size()) g[i] = (*this)[i+1] * (i+1);
		return g;
	}
	Poly intg() const {
		assert(si(invs) > size());
		Poly g(size()+1);
		rep(i,size()) g[i+1] = (*this)[i] * invs[i+1];
		return g;
	}
	Poly square() const {
		return multiply(*this,*this);
	}

	// 1/f(x) mod x^s
	// N = s = 500000 -> 90ms
	// inv は 5 回 fft(2n) を呼んでいるので、multiply が 3 回 fft(2n) を呼ぶのと比べると
	// だいたい multiply の 5/3 倍の時間がかかる
	// 導出: Newton
	// 		fg = 1 mod x^m
	// 		(fg-1)^2 = 0 mod x^2m
	// 		f(2g-fg^2) = 1 mod x^2m
	// verify: https://judge.yosupo.jp/submission/44938
	Poly inv(int s) const {
		Poly r(s);
		r[0] = mint(1)/at(0);
		for(int n=1;n<s;n*=2){			// 5 times fft : length 2n
			V<mint> f = low(2*n); f.resize(2*n);
			fft(f);
			V<mint> g = r.low(2*n); g.resize(2*n);
			fft(g);
			rep(i,2*n) f[i] *= g[i];
			invfft(f);
			rep(i,n) f[i] = 0;
			fft(f);
			rep(i,2*n) f[i] *= g[i];
			invfft(f);
			for(int i=n;i<min(2*n,s);i++) r[i] -= f[i];
		}
		return r;
	}

	// log f mod x^s
	// 導出: D log(f) = (D f) / f
	// 500000: 180ms
	// mult の 8/3 倍
	// verify: https://judge.yosupo.jp/submission/44962
	Poly log(int s) const {
		assert(at(0) == 1);
		if(s == 1) return {0};
		return (low(s).diff() * inv(s-1)).low(s-1).intg();
	}

	// e^f mod x^s
	// f.log(s).exp(s) == [1,0,...,0]
	// 500000 : 440ms
	// TODO: 高速化！
	// 速い実装例 (hos): https://judge.yosupo.jp/submission/36732 150ms
	// 導出 Newton:
	//		g = exp(f)
	//		log(g) - f = 0
	//		g == g0 mod x^m
	//		g == g0 - (log(g0) - f) / (1/g0) mod x^2m
	// verify: yosupo
	Poly exp(int s) const {
		assert(at(0) == 0);
		Poly f({1}),g({1});
		for(int n=1;n<s;n*=2){
			g = (g*2-g.square().low(n)*f).low(n);
			Poly q = low(n).diff();
			q = q + g * (f.diff() - f*q).low(2*n-1);
			f = (f + f * (low(2*n)-q.intg()) ).low(2*n);
		}
		return f.low(s);
	}

	// f^p mod x^s
	// 500000: 600ms
	// 導出: f^p = e^(p log f)
	// log 1回、 exp 1回
	// Exp.cpp (Mifafa technique) も参照
	// 	c.f. (f の non0 coef の個数) * s
	// verify: https://judge.yosupo.jp/submission/44992
	Poly pow(ll p, int s) const {
		if(p == 0){
			return Poly(s) + 1;	// 0^0 is 1
		}
		int ord = 0;
		while(ord<s && !at(ord)) ord++;
		assert(!(p<0 and ord>0));	// 頑張ればできる
		if(p>0 and (s-1)/p < ord) return Poly(s);	// s <= p * ord
		int off = p*ord;
		int s_ = s-off;
		const mint a0 = at(ord), ia0 = a0.inv(), ap = a0.pow(p);
		Poly f(s_); rep(i,s_) f[i] = at(i+ord) * ia0;
		f = (f.log(s_) * p).exp(s_);
		Poly res(s);
		rep(i,s_) res[i+off] = f[i] * ap;
		return res;
	}

	// f^(1/2) mod x^s
	// f[0] should be 1
	// 11/6
	// verify: https://judge.yosupo.jp/submission/44997
	Poly sqrt(int s) const {
		assert(at(0) == 1);
		static const mint i2 = mint(2).inv();
		V<mint> f{1},g{1},z{1};
		for(int n=1;n<s;n*=2){
			rep(i,n) z[i] *= z[i];
			invfft(z);
			V<mint> d(2*n);
			rep(i,n) d[n+i] = z[i] - at(i) - at(n+i);
			fft(d);
			V<mint> g2(2*n);
			rep(i,n) g2[i] = g[i];
			fft(g2);
			rep(i,n*2) d[i] *= g2[i];
			invfft(d);
			f.resize(n*2);
			for(int i=n;i<n*2;i++) f[i] = -d[i] * i2;
			if(n*2 >= s) break;
			z = f;
			fft(z);
			V<mint> eps = g2;
			rep(i,n*2) eps[i] *= z[i];
			invfft(eps);
			rep(i,n) eps[i] = 0;
			fft(eps);
			rep(i,n*2) eps[i] *= g2[i];
			invfft(eps);
			g.resize(n*2);
			for(int i=n;i<n*2;i++) g[i] -= eps[i];
		}
		f.resize(s);
		return f;
	}

	// Taylor Shift
	// return f(x+c)
	// O(N logN)
	// verify: yosupo
	Poly shift(mint c){
		int n = size();
		assert(si(fact) >= n);	// please InitFact
		V<mint> f(n); rep(i,n) f[i] = (*this)[i] * fact[i];
		V<mint> g(n);
		mint cpow = 1;
		rep(i,n){g[i] = cpow * ifact[i]; cpow *= c;}
		reverse(all(g));
		V<mint> h = multiply(f,g);
		Poly res(n); rep(i,n) res[i] = h[n-1+i] * ifact[i];
		return res;
	}

	// 合成逆 mod x^s
	// O(s^2 + s^1.5 log s)
	// 方針: lagrange [x^i]g = (1/i [x^i-1](x/f)^i)
	// 		(x/f)^i = (x/f)^jL (x/f)^k とすれば前計算はs^1.5回FFT
	// 		2つの積の一箇所求めるだけなのでO(s)
	// z をかけまくったり z^L をかけまくったりするところはFFT消せるから高速化できる
	// verify: https://www.luogu.com.cn/problem/P5809
	Poly compositeInv(int s){
		assert(at(0) == 0);
		assert(at(1) != 0);
		int L = 0;
		while(L*L < s) L++;
		Poly z0(s); rep(i,s) z0[i] = at(i+1);
		Poly z = z0.inv(s);	// = x/f
		V<Poly> zi(L);	// z^i
		V<Poly>	ziL(L);	// z^iL
		zi[0] = {1};
		rep(i,L-1) zi[i+1] = (zi[i] * z).low(s);
		auto zL = (zi[L-1] * z).low(s);
		ziL[0] = {1};
		rep(i,L-1)  ziL[i+1] = (ziL[i] * zL).low(s);

		Poly res(s);
		rep1(k,s-1){
			int i = k/L, j = k%L;	// x^(iL+j)
			rep(_,k) res[k] += ziL[i].at(_) * zi[j].at(k-1-_);
			res[k] /= k;
		}
		return res;
	}
};
using poly = Poly<mint>;
using P = pair<int,int>;
map<P,poly> f;

int main(){
	cin.tie(0);
	ios::sync_with_stdio(false);		//DON'T USE scanf/printf/puts !!
	cout << fixed << setprecision(20);
	InitFact(TEN(6));

	int N,S; cin >> N >> S;
	V<int> n(N),c(N);
	rep(i,N) cin >> n[i];
	rep(i,N) cin >> c[i];
	V<mint> ans(N);

	auto dfs = [&](auto& self,int l,int r)->poly{
		if(r-l == 1){
			int k = l;
			poly f_k(c[k]);
			rep(i,c[k]) f_k[i] = ifact[i] * ifact[n[k]-i];
			return f[P(l,r)] = f_k;
		}
		int m = (l+r)/2;
		return f[P(l,r)] = self(self,l,m) * self(self,m,r);
	};
	dfs(dfs,0,N);
	mint waf = 1; rep(i,N) waf *= fact[n[i]];
	// {
	//	poly g(S); rep(i,S) g[i] = fact[i] * fact[S-1-i];
	// 	mint ans_0 = (dfs(dfs,1,N) * g).at(S-c[0]) * ifact[c[0]-1] * ifact[n[0]-c[0]];
	// 	rep(i,N) ans_0 *= fact[n[i]];
	// 	cout << ans_0 << endl;
	// }

	V<int> csum(N+1); rep(i,N) csum[i+1] = csum[i] + c[i];
	// h = [x^(S-csum),..,x^S] (g * f_other)
	auto dgs = [&](auto& self, int l, int r, poly h){
		if(r-l == 1){
			int k = l;
			ans[k] = h[0] * ifact[c[k]-1] * ifact[n[k]-c[k]] * waf;
			return;
		}
		int m = (l+r)/2;
		int cl = csum[m]-csum[l], cr = csum[r]-csum[m], cs = csum[r]-csum[l];
		{
			poly ha(cs+1);
			auto tmp = h * f[P(m,r)];
			rep(i,cs+1) ha[i] = tmp.at(i+cr);
			self(self,l,m,ha);
		}
		{
			poly hb(cs+1);
			auto tmp = h * f[P(l,m)];
			rep(i,cs+1) hb[i] = tmp.at(i+cl);
			self(self,m,r,hb);
		}
	};
	poly h0(csum[N]+1);
	rep(i,csum[N]){
		int j = S-csum[N]+i;
		h0[i] = fact[j] * fact[S-1-j];
	}
	dgs(dgs,0,N,h0);
	rep(i,N) cout << ans[i] << endl;
}
accuracy: 1
time_ms: 840
memory_kb: 69792
final_rank: 4

code_snippet: /**
 *  date : 2022-12-28 20:22:59
 */

#define NDEBUG
using namespace std;

// intrinstic
#include <immintrin.h>

#include <algorithm>
#include <array>
#include <bitset>
#include <cassert>
#include <cctype>
#include <cfenv>
#include <cfloat>
#include <chrono>
#include <cinttypes>
#include <climits>
#include <cmath>
#include <complex>
#include <cstdarg>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <deque>
#include <fstream>
#include <functional>
#include <initializer_list>
#include <iomanip>
#include <ios>
#include <iostream>
#include <istream>
#include <iterator>
#include <limits>
#include <list>
#include <map>
#include <memory>
#include <new>
#include <numeric>
#include <ostream>
#include <queue>
#include <random>
#include <set>
#include <sstream>
#include <stack>
#include <streambuf>
#include <string>
#include <tuple>
#include <type_traits>
#include <typeinfo>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>

// utility
namespace Nyaan {
using ll = long long;
using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128_t;
using u128 = __uint128_t;

template <typename T>
using V = vector<T>;
template <typename T>
using VV = vector<vector<T>>;
using vi = vector<int>;
using vl = vector<long long>;
using vd = V<double>;
using vs = V<string>;
using vvi = vector<vector<int>>;
using vvl = vector<vector<long long>>;

template <typename T, typename U>
struct P : pair<T, U> {
  template <typename... Args>
  P(Args... args) : pair<T, U>(args...) {}

  using pair<T, U>::first;
  using pair<T, U>::second;

  P &operator+=(const P &r) {
    first += r.first;
    second += r.second;
    return *this;
  }
  P &operator-=(const P &r) {
    first -= r.first;
    second -= r.second;
    return *this;
  }
  P &operator*=(const P &r) {
    first *= r.first;
    second *= r.second;
    return *this;
  }
  template <typename S>
  P &operator*=(const S &r) {
    first *= r, second *= r;
    return *this;
  }
  P operator+(const P &r) const { return P(*this) += r; }
  P operator-(const P &r) const { return P(*this) -= r; }
  P operator*(const P &r) const { return P(*this) *= r; }
  template <typename S>
  P operator*(const S &r) const {
    return P(*this) *= r;
  }
  P operator-() const { return P{-first, -second}; }
};

using pl = P<ll, ll>;
using pi = P<int, int>;
using vp = V<pl>;

constexpr int inf = 1001001001;
constexpr long long infLL = 4004004004004004004LL;

template <typename T>
int sz(const T &t) {
  return t.size();
}

template <typename T, typename U>
inline bool amin(T &x, U y) {
  return (y < x) ? (x = y, true) : false;
}
template <typename T, typename U>
inline bool amax(T &x, U y) {
  return (x < y) ? (x = y, true) : false;
}

template <typename T>
inline T Max(const vector<T> &v) {
  return *max_element(begin(v), end(v));
}
template <typename T>
inline T Min(const vector<T> &v) {
  return *min_element(begin(v), end(v));
}
template <typename T>
inline long long Sum(const vector<T> &v) {
  return accumulate(begin(v), end(v), 0LL);
}

template <typename T>
int lb(const vector<T> &v, const T &a) {
  return lower_bound(begin(v), end(v), a) - begin(v);
}
template <typename T>
int ub(const vector<T> &v, const T &a) {
  return upper_bound(begin(v), end(v), a) - begin(v);
}

constexpr long long TEN(int n) {
  long long ret = 1, x = 10;
  for (; n; x *= x, n >>= 1) ret *= (n & 1 ? x : 1);
  return ret;
}

template <typename T, typename U>
pair<T, U> mkp(const T &t, const U &u) {
  return make_pair(t, u);
}

template <typename T>
vector<T> mkrui(const vector<T> &v, bool rev = false) {
  vector<T> ret(v.size() + 1);
  if (rev) {
    for (int i = int(v.size()) - 1; i >= 0; i--) ret[i] = v[i] + ret[i + 1];
  } else {
    for (int i = 0; i < int(v.size()); i++) ret[i + 1] = ret[i] + v[i];
  }
  return ret;
};

template <typename T>
vector<T> mkuni(const vector<T> &v) {
  vector<T> ret(v);
  sort(ret.begin(), ret.end());
  ret.erase(unique(ret.begin(), ret.end()), ret.end());
  return ret;
}

template <typename F>
vector<int> mkord(int N,F f) {
  vector<int> ord(N);
  iota(begin(ord), end(ord), 0);
  sort(begin(ord), end(ord), f);
  return ord;
}

template <typename T>
vector<int> mkinv(vector<T> &v) {
  int max_val = *max_element(begin(v), end(v));
  vector<int> inv(max_val + 1, -1);
  for (int i = 0; i < (int)v.size(); i++) inv[v[i]] = i;
  return inv;
}

vector<int> mkiota(int n) {
  vector<int> ret(n);
  iota(begin(ret), end(ret), 0);
  return ret;
}


template <typename T>
using minpq = priority_queue<T, vector<T>, greater<T>>;

}  // namespace Nyaan

namespace Nyaan {

template <typename T, typename U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
  os << p.first << " " << p.second;
  return os;
}
template <typename T, typename U>
istream &operator>>(istream &is, pair<T, U> &p) {
  is >> p.first >> p.second;
  return is;
}

template <typename T>
ostream &operator<<(ostream &os, const vector<T> &v) {
  int s = (int)v.size();
  for (int i = 0; i < s; i++) os << (i ? " " : "") << v[i];
  return os;
}
template <typename T>
istream &operator>>(istream &is, vector<T> &v) {
  for (auto &x : v) is >> x;
  return is;
}


void in() {}
template <typename T, class... U>
void in(T &t, U &...u) {
  cin >> t;
  in(u...);
}

void out() { cout << "\n"; }
template <typename T, class... U, char sep = ' '>
void out(const T &t, const U &...u) {
  cout << t;
  if (sizeof...(u)) cout << sep;
  out(u...);
}

void outr() {}
template <typename T, class... U, char sep = ' '>
void outr(const T &t, const U &...u) {
  cout << t;
  outr(u...);
}

struct IoSetupNya {
  IoSetupNya() {
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    cout << fixed << setprecision(15);
    cerr << fixed << setprecision(7);
  }
} iosetupnya;

}  // namespace Nyaan

// debug

#ifdef NyaanDebug
#define trc(...) (void(0))
#else
#define trc(...) (void(0))
#endif

#ifdef NyaanLocal
#define trc2(...) (void(0))
#else
#define trc2(...) (void(0))
#endif

// macro
#define each(x, v) for (auto&& x : v)
#define each2(x, y, v) for (auto&& [x, y] : v)
#define all(v) (v).begin(), (v).end()
#define rep(i, N) for (long long i = 0; i < (long long)(N); i++)
#define repr(i, N) for (long long i = (long long)(N)-1; i >= 0; i--)
#define rep1(i, N) for (long long i = 1; i <= (long long)(N); i++)
#define repr1(i, N) for (long long i = (N); (long long)(i) > 0; i--)
#define reg(i, a, b) for (long long i = (a); i < (b); i++)
#define regr(i, a, b) for (long long i = (b)-1; i >= (a); i--)
#define fi first
#define se second
#define ini(...)   \
  int __VA_ARGS__; \
  in(__VA_ARGS__)
#define inl(...)         \
  long long __VA_ARGS__; \
  in(__VA_ARGS__)
#define ins(...)      \
  string __VA_ARGS__; \
  in(__VA_ARGS__)
#define in2(s, t)                           \
  for (int i = 0; i < (int)s.size(); i++) { \
    in(s[i], t[i]);                         \
  }
#define in3(s, t, u)                        \
  for (int i = 0; i < (int)s.size(); i++) { \
    in(s[i], t[i], u[i]);                   \
  }
#define in4(s, t, u, v)                     \
  for (int i = 0; i < (int)s.size(); i++) { \
    in(s[i], t[i], u[i], v[i]);             \
  }
#define die(...)             \
  do {                       \
    Nyaan::out(__VA_ARGS__); \
    return;                  \
  } while (0)

namespace Nyaan {
void solve();
}
int main() { Nyaan::solve(); }

//


template <typename mint>
struct NTT {
  static constexpr uint32_t get_pr() {
    uint32_t _mod = mint::get_mod();
    using u64 = uint64_t;
    u64 ds[32] = {};
    int idx = 0;
    u64 m = _mod - 1;
    for (u64 i = 2; i * i <= m; ++i) {
      if (m % i == 0) {
        ds[idx++] = i;
        while (m % i == 0) m /= i;
      }
    }
    if (m != 1) ds[idx++] = m;

    uint32_t _pr = 2;
    while (1) {
      int flg = 1;
      for (int i = 0; i < idx; ++i) {
        u64 a = _pr, b = (_mod - 1) / ds[i], r = 1;
        while (b) {
          if (b & 1) r = r * a % _mod;
          a = a * a % _mod;
          b >>= 1;
        }
        if (r == 1) {
          flg = 0;
          break;
        }
      }
      if (flg == 1) break;
      ++_pr;
    }
    return _pr;
  };

  static constexpr uint32_t mod = mint::get_mod();
  static constexpr uint32_t pr = get_pr();
  static constexpr int level = __builtin_ctzll(mod - 1);
  mint dw[level], dy[level];

  void setwy(int k) {
    mint w[level], y[level];
    w[k - 1] = mint(pr).pow((mod - 1) / (1 << k));
    y[k - 1] = w[k - 1].inverse();
    for (int i = k - 2; i > 0; --i)
      w[i] = w[i + 1] * w[i + 1], y[i] = y[i + 1] * y[i + 1];
    dw[1] = w[1], dy[1] = y[1], dw[2] = w[2], dy[2] = y[2];
    for (int i = 3; i < k; ++i) {
      dw[i] = dw[i - 1] * y[i - 2] * w[i];
      dy[i] = dy[i - 1] * w[i - 2] * y[i];
    }
  }

  NTT() { setwy(level); }

  void fft4(vector<mint> &a, int k) {
    if ((int)a.size() <= 1) return;
    if (k == 1) {
      mint a1 = a[1];
      a[1] = a[0] - a[1];
      a[0] = a[0] + a1;
      return;
    }
    if (k & 1) {
      int v = 1 << (k - 1);
      for (int j = 0; j < v; ++j) {
        mint ajv = a[j + v];
        a[j + v] = a[j] - ajv;
        a[j] += ajv;
      }
    }
    int u = 1 << (2 + (k & 1));
    int v = 1 << (k - 2 - (k & 1));
    mint one = mint(1);
    mint imag = dw[1];
    while (v) {
      // jh = 0
      {
        int j0 = 0;
        int j1 = v;
        int j2 = j1 + v;
        int j3 = j2 + v;
        for (; j0 < v; ++j0, ++j1, ++j2, ++j3) {
          mint t0 = a[j0], t1 = a[j1], t2 = a[j2], t3 = a[j3];
          mint t0p2 = t0 + t2, t1p3 = t1 + t3;
          mint t0m2 = t0 - t2, t1m3 = (t1 - t3) * imag;
          a[j0] = t0p2 + t1p3, a[j1] = t0p2 - t1p3;
          a[j2] = t0m2 + t1m3, a[j3] = t0m2 - t1m3;
        }
      }
      // jh >= 1
      mint ww = one, xx = one * dw[2], wx = one;
      for (int jh = 4; jh < u;) {
        ww = xx * xx, wx = ww * xx;
        int j0 = jh * v;
        int je = j0 + v;
        int j2 = je + v;
        for (; j0 < je; ++j0, ++j2) {
          mint t0 = a[j0], t1 = a[j0 + v] * xx, t2 = a[j2] * ww,
               t3 = a[j2 + v] * wx;
          mint t0p2 = t0 + t2, t1p3 = t1 + t3;
          mint t0m2 = t0 - t2, t1m3 = (t1 - t3) * imag;
          a[j0] = t0p2 + t1p3, a[j0 + v] = t0p2 - t1p3;
          a[j2] = t0m2 + t1m3, a[j2 + v] = t0m2 - t1m3;
        }
        xx *= dw[__builtin_ctzll((jh += 4))];
      }
      u <<= 2;
      v >>= 2;
    }
  }

  void ifft4(vector<mint> &a, int k) {
    if ((int)a.size() <= 1) return;
    if (k == 1) {
      mint a1 = a[1];
      a[1] = a[0] - a[1];
      a[0] = a[0] + a1;
      return;
    }
    int u = 1 << (k - 2);
    int v = 1;
    mint one = mint(1);
    mint imag = dy[1];
    while (u) {
      // jh = 0
      {
        int j0 = 0;
        int j1 = v;
        int j2 = v + v;
        int j3 = j2 + v;
        for (; j0 < v; ++j0, ++j1, ++j2, ++j3) {
          mint t0 = a[j0], t1 = a[j1], t2 = a[j2], t3 = a[j3];
          mint t0p1 = t0 + t1, t2p3 = t2 + t3;
          mint t0m1 = t0 - t1, t2m3 = (t2 - t3) * imag;
          a[j0] = t0p1 + t2p3, a[j2] = t0p1 - t2p3;
          a[j1] = t0m1 + t2m3, a[j3] = t0m1 - t2m3;
        }
      }
      // jh >= 1
      mint ww = one, xx = one * dy[2], yy = one;
      u <<= 2;
      for (int jh = 4; jh < u;) {
        ww = xx * xx, yy = xx * imag;
        int j0 = jh * v;
        int je = j0 + v;
        int j2 = je + v;
        for (; j0 < je; ++j0, ++j2) {
          mint t0 = a[j0], t1 = a[j0 + v], t2 = a[j2], t3 = a[j2 + v];
          mint t0p1 = t0 + t1, t2p3 = t2 + t3;
          mint t0m1 = (t0 - t1) * xx, t2m3 = (t2 - t3) * yy;
          a[j0] = t0p1 + t2p3, a[j2] = (t0p1 - t2p3) * ww;
          a[j0 + v] = t0m1 + t2m3, a[j2 + v] = (t0m1 - t2m3) * ww;
        }
        xx *= dy[__builtin_ctzll(jh += 4)];
      }
      u >>= 4;
      v <<= 2;
    }
    if (k & 1) {
      u = 1 << (k - 1);
      for (int j = 0; j < u; ++j) {
        mint ajv = a[j] - a[j + u];
        a[j] += a[j + u];
        a[j + u] = ajv;
      }
    }
  }

  void ntt(vector<mint> &a) {
    if ((int)a.size() <= 1) return;
    fft4(a, __builtin_ctz(a.size()));
  }

  void intt(vector<mint> &a) {
    if ((int)a.size() <= 1) return;
    ifft4(a, __builtin_ctz(a.size()));
    mint iv = mint(a.size()).inverse();
    for (auto &x : a) x *= iv;
  }

  vector<mint> multiply(const vector<mint> &a, const vector<mint> &b) {
    int l = a.size() + b.size() - 1;
    if (min<int>(a.size(), b.size()) <= 40) {
      vector<mint> s(l);
      for (int i = 0; i < (int)a.size(); ++i)
        for (int j = 0; j < (int)b.size(); ++j) s[i + j] += a[i] * b[j];
      return s;
    }
    int k = 2, M = 4;
    while (M < l) M <<= 1, ++k;
    setwy(k);
    vector<mint> s(M), t(M);
    for (int i = 0; i < (int)a.size(); ++i) s[i] = a[i];
    for (int i = 0; i < (int)b.size(); ++i) t[i] = b[i];
    fft4(s, k);
    fft4(t, k);
    for (int i = 0; i < M; ++i) s[i] *= t[i];
    ifft4(s, k);
    s.resize(l);
    mint invm = mint(M).inverse();
    for (int i = 0; i < l; ++i) s[i] *= invm;
    return s;
  }

  void ntt_doubling(vector<mint> &a) {
    int M = (int)a.size();
    auto b = a;
    intt(b);
    mint r = 1, zeta = mint(pr).pow((mint::get_mod() - 1) / (M << 1));
    for (int i = 0; i < M; i++) b[i] *= r, r *= zeta;
    ntt(b);
    copy(begin(b), end(b), back_inserter(a));
  }
};

template <typename mint>
struct FormalPowerSeries : vector<mint> {
  using vector<mint>::vector;
  using FPS = FormalPowerSeries;

  FPS &operator+=(const FPS &r) {
    if (r.size() > this->size()) this->resize(r.size());
    for (int i = 0; i < (int)r.size(); i++) (*this)[i] += r[i];
    return *this;
  }

  FPS &operator+=(const mint &r) {
    if (this->empty()) this->resize(1);
    (*this)[0] += r;
    return *this;
  }

  FPS &operator-=(const FPS &r) {
    if (r.size() > this->size()) this->resize(r.size());
    for (int i = 0; i < (int)r.size(); i++) (*this)[i] -= r[i];
    return *this;
  }

  FPS &operator-=(const mint &r) {
    if (this->empty()) this->resize(1);
    (*this)[0] -= r;
    return *this;
  }

  FPS &operator*=(const mint &v) {
    for (int k = 0; k < (int)this->size(); k++) (*this)[k] *= v;
    return *this;
  }

  FPS &operator/=(const FPS &r) {
    if (this->size() < r.size()) {
      this->clear();
      return *this;
    }
    int n = this->size() - r.size() + 1;
    if ((int)r.size() <= 64) {
      FPS f(*this), g(r);
      g.shrink();
      mint coeff = g.back().inverse();
      for (auto &x : g) x *= coeff;
      int deg = (int)f.size() - (int)g.size() + 1;
      int gs = g.size();
      FPS quo(deg);
      for (int i = deg - 1; i >= 0; i--) {
        quo[i] = f[i + gs - 1];
        for (int j = 0; j < gs; j++) f[i + j] -= quo[i] * g[j];
      }
      *this = quo * coeff;
      this->resize(n, mint(0));
      return *this;
    }
    return *this = ((*this).rev().pre(n) * r.rev().inv(n)).pre(n).rev();
  }

  FPS &operator%=(const FPS &r) {
    *this -= *this / r * r;
    shrink();
    return *this;
  }

  FPS operator+(const FPS &r) const { return FPS(*this) += r; }
  FPS operator+(const mint &v) const { return FPS(*this) += v; }
  FPS operator-(const FPS &r) const { return FPS(*this) -= r; }
  FPS operator-(const mint &v) const { return FPS(*this) -= v; }
  FPS operator*(const FPS &r) const { return FPS(*this) *= r; }
  FPS operator*(const mint &v) const { return FPS(*this) *= v; }
  FPS operator/(const FPS &r) const { return FPS(*this) /= r; }
  FPS operator%(const FPS &r) const { return FPS(*this) %= r; }
  FPS operator-() const {
    FPS ret(this->size());
    for (int i = 0; i < (int)this->size(); i++) ret[i] = -(*this)[i];
    return ret;
  }

  void shrink() {
    while (this->size() && this->back() == mint(0)) this->pop_back();
  }

  FPS rev() const {
    FPS ret(*this);
    reverse(begin(ret), end(ret));
    return ret;
  }

  FPS dot(FPS r) const {
    FPS ret(min(this->size(), r.size()));
    for (int i = 0; i < (int)ret.size(); i++) ret[i] = (*this)[i] * r[i];
    return ret;
  }

  FPS pre(int sz) const {
    return FPS(begin(*this), begin(*this) + min((int)this->size(), sz));
  }

  FPS operator>>(int sz) const {
    if ((int)this->size() <= sz) return {};
    FPS ret(*this);
    ret.erase(ret.begin(), ret.begin() + sz);
    return ret;
  }

  FPS operator<<(int sz) const {
    FPS ret(*this);
    ret.insert(ret.begin(), sz, mint(0));
    return ret;
  }

  FPS diff() const {
    const int n = (int)this->size();
    FPS ret(max(0, n - 1));
    mint one(1), coeff(1);
    for (int i = 1; i < n; i++) {
      ret[i - 1] = (*this)[i] * coeff;
      coeff += one;
    }
    return ret;
  }

  FPS integral() const {
    const int n = (int)this->size();
    FPS ret(n + 1);
    ret[0] = mint(0);
    if (n > 0) ret[1] = mint(1);
    auto mod = mint::get_mod();
    for (int i = 2; i <= n; i++) ret[i] = (-ret[mod % i]) * (mod / i);
    for (int i = 0; i < n; i++) ret[i + 1] *= (*this)[i];
    return ret;
  }

  mint eval(mint x) const {
    mint r = 0, w = 1;
    for (auto &v : *this) r += w * v, w *= x;
    return r;
  }

  FPS log(int deg = -1) const {
    assert((*this)[0] == mint(1));
    if (deg == -1) deg = (int)this->size();
    return (this->diff() * this->inv(deg)).pre(deg - 1).integral();
  }

  FPS pow(int64_t k, int deg = -1) const {
    const int n = (int)this->size();
    if (deg == -1) deg = n;
    if (k == 0) {
      FPS ret(deg);
      if (deg) ret[0] = 1;
      return ret;
    }
    for (int i = 0; i < n; i++) {
      if ((*this)[i] != mint(0)) {
        mint rev = mint(1) / (*this)[i];
        FPS ret = (((*this * rev) >> i).log(deg) * k).exp(deg);
        ret *= (*this)[i].pow(k);
        ret = (ret << (i * k)).pre(deg);
        if ((int)ret.size() < deg) ret.resize(deg, mint(0));
        return ret;
      }
      if (__int128_t(i + 1) * k >= deg) return FPS(deg, mint(0));
    }
    return FPS(deg, mint(0));
  }

  static void *ntt_ptr;
  static void set_fft();
  FPS &operator*=(const FPS &r);
  void ntt();
  void intt();
  void ntt_doubling();
  static int ntt_pr();
  FPS inv(int deg = -1) const;
  FPS exp(int deg = -1) const;
};
template <typename mint>
void *FormalPowerSeries<mint>::ntt_ptr = nullptr;

/**
 * @brief 多項式/形式的冪級数ライブラリ
 * @docs docs/fps/formal-power-series.md
 */

template <typename mint>
void FormalPowerSeries<mint>::set_fft() {
  if (!ntt_ptr) ntt_ptr = new NTT<mint>;
}

template <typename mint>
FormalPowerSeries<mint>& FormalPowerSeries<mint>::operator*=(
    const FormalPowerSeries<mint>& r) {
  if (this->empty() || r.empty()) {
    this->clear();
    return *this;
  }
  set_fft();
  auto ret = static_cast<NTT<mint>*>(ntt_ptr)->multiply(*this, r);
  return *this = FormalPowerSeries<mint>(ret.begin(), ret.end());
}

template <typename mint>
void FormalPowerSeries<mint>::ntt() {
  set_fft();
  static_cast<NTT<mint>*>(ntt_ptr)->ntt(*this);
}

template <typename mint>
void FormalPowerSeries<mint>::intt() {
  set_fft();
  static_cast<NTT<mint>*>(ntt_ptr)->intt(*this);
}

template <typename mint>
void FormalPowerSeries<mint>::ntt_doubling() {
  set_fft();
  static_cast<NTT<mint>*>(ntt_ptr)->ntt_doubling(*this);
}

template <typename mint>
int FormalPowerSeries<mint>::ntt_pr() {
  set_fft();
  return static_cast<NTT<mint>*>(ntt_ptr)->pr;
}

template <typename mint>
FormalPowerSeries<mint> FormalPowerSeries<mint>::inv(int deg) const {
  assert((*this)[0] != mint(0));
  if (deg == -1) deg = (int)this->size();
  FormalPowerSeries<mint> res(deg);
  res[0] = {mint(1) / (*this)[0]};
  for (int d = 1; d < deg; d <<= 1) {
    FormalPowerSeries<mint> f(2 * d), g(2 * d);
    for (int j = 0; j < min((int)this->size(), 2 * d); j++) f[j] = (*this)[j];
    for (int j = 0; j < d; j++) g[j] = res[j];
    f.ntt();
    g.ntt();
    for (int j = 0; j < 2 * d; j++) f[j] *= g[j];
    f.intt();
    for (int j = 0; j < d; j++) f[j] = 0;
    f.ntt();
    for (int j = 0; j < 2 * d; j++) f[j] *= g[j];
    f.intt();
    for (int j = d; j < min(2 * d, deg); j++) res[j] = -f[j];
  }
  return res.pre(deg);
}

template <typename mint>
FormalPowerSeries<mint> FormalPowerSeries<mint>::exp(int deg) const {
  using fps = FormalPowerSeries<mint>;
  assert((*this).size() == 0 || (*this)[0] == mint(0));
  if (deg == -1) deg = this->size();

  fps inv;
  inv.reserve(deg + 1);
  inv.push_back(mint(0));
  inv.push_back(mint(1));

  auto inplace_integral = [&](fps& F) -> void {
    const int n = (int)F.size();
    auto mod = mint::get_mod();
    while ((int)inv.size() <= n) {
      int i = inv.size();
      inv.push_back((-inv[mod % i]) * (mod / i));
    }
    F.insert(begin(F), mint(0));
    for (int i = 1; i <= n; i++) F[i] *= inv[i];
  };

  auto inplace_diff = [](fps& F) -> void {
    if (F.empty()) return;
    F.erase(begin(F));
    mint coeff = 1, one = 1;
    for (int i = 0; i < (int)F.size(); i++) {
      F[i] *= coeff;
      coeff += one;
    }
  };

  fps b{1, 1 < (int)this->size() ? (*this)[1] : 0}, c{1}, z1, z2{1, 1};
  for (int m = 2; m < deg; m *= 2) {
    auto y = b;
    y.resize(2 * m);
    y.ntt();
    z1 = z2;
    fps z(m);
    for (int i = 0; i < m; ++i) z[i] = y[i] * z1[i];
    z.intt();
    fill(begin(z), begin(z) + m / 2, mint(0));
    z.ntt();
    for (int i = 0; i < m; ++i) z[i] *= -z1[i];
    z.intt();
    c.insert(end(c), begin(z) + m / 2, end(z));
    z2 = c;
    z2.resize(2 * m);
    z2.ntt();
    fps x(begin(*this), begin(*this) + min<int>(this->size(), m));
    x.resize(m);
    inplace_diff(x);
    x.push_back(mint(0));
    x.ntt();
    for (int i = 0; i < m; ++i) x[i] *= y[i];
    x.intt();
    x -= b.diff();
    x.resize(2 * m);
    for (int i = 0; i < m - 1; ++i) x[m + i] = x[i], x[i] = mint(0);
    x.ntt();
    for (int i = 0; i < 2 * m; ++i) x[i] *= z2[i];
    x.intt();
    x.pop_back();
    inplace_integral(x);
    for (int i = m; i < min<int>(this->size(), 2 * m); ++i) x[i] += (*this)[i];
    fill(begin(x), begin(x) + m, mint(0));
    x.ntt();
    for (int i = 0; i < 2 * m; ++i) x[i] *= y[i];
    x.intt();
    b.insert(end(b), begin(x) + m, end(x));
  }
  return fps{begin(b), begin(b) + deg};
}

/**
 * @brief NTT mod用FPSライブラリ
 * @docs docs/fps/ntt-friendly-fps.md
 */




template <uint32_t mod>
struct LazyMontgomeryModInt {
  using mint = LazyMontgomeryModInt;
  using i32 = int32_t;
  using u32 = uint32_t;
  using u64 = uint64_t;

  static constexpr u32 get_r() {
    u32 ret = mod;
    for (i32 i = 0; i < 4; ++i) ret *= 2 - mod * ret;
    return ret;
  }

  static constexpr u32 r = get_r();
  static constexpr u32 n2 = -u64(mod) % mod;
  static_assert(r * mod == 1, "invalid, r * mod != 1");
  static_assert(mod < (1 << 30), "invalid, mod >= 2 ^ 30");
  static_assert((mod & 1) == 1, "invalid, mod % 2 == 0");

  u32 a;

  constexpr LazyMontgomeryModInt() : a(0) {}
  constexpr LazyMontgomeryModInt(const int64_t &b)
      : a(reduce(u64(b % mod + mod) * n2)){};

  static constexpr u32 reduce(const u64 &b) {
    return (b + u64(u32(b) * u32(-r)) * mod) >> 32;
  }

  constexpr mint &operator+=(const mint &b) {
    if (i32(a += b.a - 2 * mod) < 0) a += 2 * mod;
    return *this;
  }

  constexpr mint &operator-=(const mint &b) {
    if (i32(a -= b.a) < 0) a += 2 * mod;
    return *this;
  }

  constexpr mint &operator*=(const mint &b) {
    a = reduce(u64(a) * b.a);
    return *this;
  }

  constexpr mint &operator/=(const mint &b) {
    *this *= b.inverse();
    return *this;
  }

  constexpr mint operator+(const mint &b) const { return mint(*this) += b; }
  constexpr mint operator-(const mint &b) const { return mint(*this) -= b; }
  constexpr mint operator*(const mint &b) const { return mint(*this) *= b; }
  constexpr mint operator/(const mint &b) const { return mint(*this) /= b; }
  constexpr bool operator==(const mint &b) const {
    return (a >= mod ? a - mod : a) == (b.a >= mod ? b.a - mod : b.a);
  }
  constexpr bool operator!=(const mint &b) const {
    return (a >= mod ? a - mod : a) != (b.a >= mod ? b.a - mod : b.a);
  }
  constexpr mint operator-() const { return mint() - mint(*this); }

  constexpr mint pow(u64 n) const {
    mint ret(1), mul(*this);
    while (n > 0) {
      if (n & 1) ret *= mul;
      mul *= mul;
      n >>= 1;
    }
    return ret;
  }
  
  constexpr mint inverse() const { return pow(mod - 2); }

  friend ostream &operator<<(ostream &os, const mint &b) {
    return os << b.get();
  }

  friend istream &operator>>(istream &is, mint &b) {
    int64_t t;
    is >> t;
    b = LazyMontgomeryModInt<mod>(t);
    return (is);
  }
  
  constexpr u32 get() const {
    u32 ret = reduce(a);
    return ret >= mod ? ret - mod : ret;
  }

  static constexpr u32 get_mod() { return mod; }
};

template <typename T>
struct Binomial {
  vector<T> f, g, h;
  Binomial(int MAX = 0) {
    assert(T::get_mod() != 0 && "Binomial<mint>()");
    f.resize(1, T{1});
    g.resize(1, T{1});
    h.resize(1, T{1});
    while (MAX >= (int)f.size()) extend();
  }

  void extend() {
    int n = f.size();
    int m = n * 2;
    f.resize(m);
    g.resize(m);
    h.resize(m);
    for (int i = n; i < m; i++) f[i] = f[i - 1] * T(i);
    g[m - 1] = f[m - 1].inverse();
    h[m - 1] = g[m - 1] * f[m - 2];
    for (int i = m - 2; i >= n; i--) {
      g[i] = g[i + 1] * T(i + 1);
      h[i] = g[i] * f[i - 1];
    }
  }

  T fac(int i) {
    if (i < 0) return T(0);
    while (i >= (int)f.size()) extend();
    return f[i];
  }

  T finv(int i) {
    if (i < 0) return T(0);
    while (i >= (int)g.size()) extend();
    return g[i];
  }

  T inv(int i) {
    if (i < 0) return -inv(-i);
    while (i >= (int)h.size()) extend();
    return h[i];
  }

  T C(int n, int r) {
    if (n < 0 || n < r || r < 0) return T(0);
    return fac(n) * finv(n - r) * finv(r);
  }

  inline T operator()(int n, int r) { return C(n, r); }

  template <typename I>
  T multinomial(const vector<I>& r) {
    static_assert(is_integral<I>::value == true);
    int n = 0;
    for (auto& x : r) {
      if (x < 0) return T(0);
      n += x;
    }
    T res = fac(n);
    for (auto& x : r) res *= finv(x);
    return res;
  }

  template <typename I>
  T operator()(const vector<I>& r) {
    return multinomial(r);
  }

  T C_naive(int n, int r) {
    if (n < 0 || n < r || r < 0) return T(0);
    T ret = T(1);
    r = min(r, n - r);
    for (int i = 1; i <= r; ++i) ret *= inv(i) * (n--);
    return ret;
  }

  T P(int n, int r) {
    if (n < 0 || n < r || r < 0) return T(0);
    return fac(n) * finv(n - r);
  }

  // [x^r] 1 / (1-x)^n
  T H(int n, int r) {
    if (n < 0 || r < 0) return T(0);
    return r == 0 ? 1 : C(n + r - 1, r);
  }
};

//
using namespace Nyaan;
using mint = LazyMontgomeryModInt<998244353>;
// using mint = LazyMontgomeryModInt<1000000007>;
using vm = vector<mint>;
using vvm = vector<vm>;
Binomial<mint> C;
using fps = FormalPowerSeries<mint>;

using namespace Nyaan;

void q() {
  inl(N, M);
  vl A(N), B(N);
  in(A, B);
  V<fps> fs;
  rep(i, N) {
    fps f(A[i] + 1);
    mint coeff = 1;
    reg(j, 0, B[i]) {
      f[j] = C.finv(j) * coeff;
      coeff *= mint{A[i] - j};
    }
    fs.push_back(f);
  }

  fps D(M);
  rep(i, M) D[i] = C(M - 1, i).inverse() * C.fac(M - 1);

  V<pl> qs;
  rep(i, N) qs.push_back(pl{M - B[i], i});
  sort(all(qs));
  vm ans(N);

  int X = 1;
  while (X < N) X *= 2;

  V<fps> mod(2 * X, fps{1});
  vi mn(2 * X, M), mx(2 * X, M);
  rep(i, N) {
    mod[X + i] = fs[qs[i].se];
    mn[X + i] = mx[X + i] = qs[i].fi;
  }
  for (int i = X - 1; i > 0; i--) {
    mod[i] = mod[2 * i] * mod[2 * i + 1];
    mn[i] = mn[2 * i];
    mx[i] = mx[2 * i + 1];
  }

  auto dc = [&](auto rc, int idx, int l, int r, int of, fps f) -> void {
    trc(idx, l, r, of, sz(f));
    if (N <= l) return;
    // min -> max(mn[i], mx[i] - deg(mod) + 1)
    // max -> mx[i]
    int cmn = min<int>(mn[idx], mx[idx] - sz(mod[idx]));
    if (cmn < 0) cmn = 0;
    int cmx = mx[idx] + 1;
    trc(cmn, cmx);
    if (of < cmn) {
      f.erase(begin(f), begin(f) + (cmn - of));
      of = cmn;
    }
    f.resize(cmx - cmn);
    if (l + 1 == r) {
      ans[qs[l].se] = f[qs[l].fi - of];
      return;
    }
    int m = (l + r) / 2;
    rc(rc, idx * 2 + 0, l, m, of, f * mod[2 * idx + 1]);
    rc(rc, idx * 2 + 1, m, r, of, f * mod[2 * idx + 0]);
  };
  dc(dc, 1, 0, X, 0, D);
  /*
  rep(i, N) {
    auto F = Pi(fs);
    F *= D;
    F /= fs[i];
    ans[i] = F[M - B[i]];
  }
  */
  rep(i, N) { out(ans[i] * C(A[i], B[i]) * B[i]); }
}

void Nyaan::solve() {
  int t = 1;
  // in(t);
  while (t--) q();
}
accuracy: 1
time_ms: 560
memory_kb: 75984
final_rank: 2

code_snippet: #define NDEBUG
using namespace std;


#include <immintrin.h>

#include <algorithm>
#include <array>
#include <bitset>
#include <cassert>
#include <cctype>
#include <cfenv>
#include <cfloat>
#include <chrono>
#include <cinttypes>
#include <climits>
#include <cmath>
#include <complex>
#include <cstdarg>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <deque>
#include <fstream>
#include <functional>
#include <initializer_list>
#include <iomanip>
#include <ios>
#include <iostream>
#include <istream>
#include <iterator>
#include <limits>
#include <list>
#include <map>
#include <memory>
#include <new>
#include <numeric>
#include <ostream>
#include <queue>
#include <random>
#include <set>
#include <sstream>
#include <stack>
#include <streambuf>
#include <string>
#include <tuple>
#include <type_traits>
#include <typeinfo>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>


namespace Nyaan {
using ll = long long;
using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128_t;
using u128 = __uint128_t;

template <typename T>
using V = vector<T>;
template <typename T>
using VV = vector<vector<T>>;
using vi = vector<int>;
using vl = vector<long long>;
using vd = V<double>;
using vs = V<string>;
using vvi = vector<vector<int>>;
using vvl = vector<vector<long long>>;

template <typename T, typename U>
struct P : pair<T, U> {
 template <typename... Args>
 P(Args... args) : pair<T, U>(args...) {}

 using pair<T, U>::first;
 using pair<T, U>::second;

 P &operator+=(const P &r) {
 first += r.first;
 second += r.second;
 return *this;
 }
 P &operator-=(const P &r) {
 first -= r.first;
 second -= r.second;
 return *this;
 }
 P &operator*=(const P &r) {
 first *= r.first;
 second *= r.second;
 return *this;
 }
 template <typename S>
 P &operator*=(const S &r) {
 first *= r, second *= r;
 return *this;
 }
 P operator+(const P &r) const { return P(*this) += r; }
 P operator-(const P &r) const { return P(*this) -= r; }
 P operator*(const P &r) const { return P(*this) *= r; }
 template <typename S>
 P operator*(const S &r) const {
 return P(*this) *= r;
 }
 P operator-() const { return P{-first, -second}; }
};

using pl = P<ll, ll>;
using pi = P<int, int>;
using vp = V<pl>;

constexpr int inf = 1001001001;
constexpr long long infLL = 4004004004004004004LL;

template <typename T>
int sz(const T &t) {
 return t.size();
}

template <typename T, typename U>
inline bool amin(T &x, U y) {
 return (y < x) ? (x = y, true) : false;
}
template <typename T, typename U>
inline bool amax(T &x, U y) {
 return (x < y) ? (x = y, true) : false;
}

template <typename T>
inline T Max(const vector<T> &v) {
 return *max_element(begin(v), end(v));
}
template <typename T>
inline T Min(const vector<T> &v) {
 return *min_element(begin(v), end(v));
}
template <typename T>
inline long long Sum(const vector<T> &v) {
 return accumulate(begin(v), end(v), 0LL);
}

template <typename T>
int lb(const vector<T> &v, const T &a) {
 return lower_bound(begin(v), end(v), a) - begin(v);
}
template <typename T>
int ub(const vector<T> &v, const T &a) {
 return upper_bound(begin(v), end(v), a) - begin(v);
}

constexpr long long TEN(int n) {
 long long ret = 1, x = 10;
 for (; n; x *= x, n >>= 1) ret *= (n & 1 ? x : 1);
 return ret;
}

template <typename T, typename U>
pair<T, U> mkp(const T &t, const U &u) {
 return make_pair(t, u);
}

template <typename T>
vector<T> mkrui(const vector<T> &v, bool rev = false) {
 vector<T> ret(v.size() + 1);
 if (rev) {
 for (int i = int(v.size()) - 1; i >= 0; i--) ret[i] = v[i] + ret[i + 1];
 } else {
 for (int i = 0; i < int(v.size()); i++) ret[i + 1] = ret[i] + v[i];
 }
 return ret;
};

template <typename T>
vector<T> mkuni(const vector<T> &v) {
 vector<T> ret(v);
 sort(ret.begin(), ret.end());
 ret.erase(unique(ret.begin(), ret.end()), ret.end());
 return ret;
}

template <typename F>
vector<int> mkord(int N,F f) {
 vector<int> ord(N);
 iota(begin(ord), end(ord), 0);
 sort(begin(ord), end(ord), f);
 return ord;
}

template <typename T>
vector<int> mkinv(vector<T> &v) {
 int max_val = *max_element(begin(v), end(v));
 vector<int> inv(max_val + 1, -1);
 for (int i = 0; i < (int)v.size(); i++) inv[v[i]] = i;
 return inv;
}

vector<int> mkiota(int n) {
 vector<int> ret(n);
 iota(begin(ret), end(ret), 0);
 return ret;
}

template <typename T>
T mkrev(const T &v) {
 T w{v};
 reverse(begin(w), end(w));
 return w;
}

template <typename T>
bool nxp(vector<T> &v) {
 return next_permutation(begin(v), end(v));
}

template <typename T>
using minpq = priority_queue<T, vector<T>, greater<T>>;

} 


namespace Nyaan {
__attribute__((target("popcnt"))) inline int popcnt(const u64 &a) {
 return _mm_popcnt_u64(a);
}
inline int lsb(const u64 &a) { return a ? __builtin_ctzll(a) : 64; }
inline int ctz(const u64 &a) { return a ? __builtin_ctzll(a) : 64; }
inline int msb(const u64 &a) { return a ? 63 - __builtin_clzll(a) : -1; }
template <typename T>
inline int gbit(const T &a, int i) {
 return (a >> i) & 1;
}
template <typename T>
inline void sbit(T &a, int i, bool b) {
 if (gbit(a, i) != b) a ^= T(1) << i;
}
constexpr long long PW(int n) { return 1LL << n; }
constexpr long long MSK(int n) { return (1LL << n) - 1; }
} 


namespace Nyaan {

template <typename T, typename U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
 os << p.first << " " << p.second;
 return os;
}
template <typename T, typename U>
istream &operator>>(istream &is, pair<T, U> &p) {
 is >> p.first >> p.second;
 return is;
}

template <typename T>
ostream &operator<<(ostream &os, const vector<T> &v) {
 int s = (int)v.size();
 for (int i = 0; i < s; i++) os << (i ? " " : "") << v[i];
 return os;
}
template <typename T>
istream &operator>>(istream &is, vector<T> &v) {
 for (auto &x : v) is >> x;
 return is;
}

istream &operator>>(istream &is, __int128_t &x) {
 string S;
 is >> S;
 x = 0;
 int flag = 0;
 for (auto &c : S) {
 if (c == '-') {
 flag = true;
 continue;
 }
 x *= 10;
 x += c - '0';
 }
 if (flag) x = -x;
 return is;
}

istream &operator>>(istream &is, __uint128_t &x) {
 string S;
 is >> S;
 x = 0;
 for (auto &c : S) {
 x *= 10;
 x += c - '0';
 }
 return is;
}

ostream &operator<<(ostream &os, __int128_t x) {
 if (x == 0) return os << 0;
 if (x < 0) os << '-', x = -x;
 string S;
 while (x) S.push_back('0' + x % 10), x /= 10;
 reverse(begin(S), end(S));
 return os << S;
}
ostream &operator<<(ostream &os, __uint128_t x) {
 if (x == 0) return os << 0;
 string S;
 while (x) S.push_back('0' + x % 10), x /= 10;
 reverse(begin(S), end(S));
 return os << S;
}

void in() {}
template <typename T, class... U>
void in(T &t, U &...u) {
 cin >> t;
 in(u...);
}

void out() { cout << "\n"; }
template <typename T, class... U, char sep = ' '>
void out(const T &t, const U &...u) {
 cout << t;
 if (sizeof...(u)) cout << sep;
 out(u...);
}

void outr() {}
template <typename T, class... U, char sep = ' '>
void outr(const T &t, const U &...u) {
 cout << t;
 outr(u...);
}

struct IoSetupNya {
 IoSetupNya() {
 cin.tie(nullptr);
 ios::sync_with_stdio(false);
 cout << fixed << setprecision(15);
 cerr << fixed << setprecision(7);
 }
} iosetupnya;

} 



#ifdef NyaanDebug
#define trc(...) (void(0))
#else
#define trc(...) (void(0))
#endif

#ifdef NyaanLocal
#define trc2(...) (void(0))
#else
#define trc2(...) (void(0))
#endif


#define each(x, v) for (auto&& x : v)
#define each2(x, y, v) for (auto&& [x, y] : v)
#define all(v) (v).begin(), (v).end()
#define rep(i, N) for (long long i = 0; i < (long long)(N); i++)
#define repr(i, N) for (long long i = (long long)(N)-1; i >= 0; i--)
#define rep1(i, N) for (long long i = 1; i <= (long long)(N); i++)
#define repr1(i, N) for (long long i = (N); (long long)(i) > 0; i--)
#define reg(i, a, b) for (long long i = (a); i < (b); i++)
#define regr(i, a, b) for (long long i = (b)-1; i >= (a); i--)
#define fi first
#define se second
#define ini(...) \
 int __VA_ARGS__; \
 in(__VA_ARGS__)
#define inl(...) \
 long long __VA_ARGS__; \
 in(__VA_ARGS__)
#define ins(...) \
 string __VA_ARGS__; \
 in(__VA_ARGS__)
#define in2(s, t) \
 for (int i = 0; i < (int)s.size(); i++) { \
 in(s[i], t[i]); \
 }
#define in3(s, t, u) \
 for (int i = 0; i < (int)s.size(); i++) { \
 in(s[i], t[i], u[i]); \
 }
#define in4(s, t, u, v) \
 for (int i = 0; i < (int)s.size(); i++) { \
 in(s[i], t[i], u[i], v[i]); \
 }
#define die(...) \
 do { \
 Nyaan::out(__VA_ARGS__); \
 return; \
 } while (0)

namespace Nyaan {
void solve();
}
int main() { Nyaan::solve(); }




template <typename mint>
struct NTT {
 static constexpr uint32_t get_pr() {
 uint32_t _mod = mint::get_mod();
 using u64 = uint64_t;
 u64 ds[32] = {};
 int idx = 0;
 u64 m = _mod - 1;
 for (u64 i = 2; i * i <= m; ++i) {
 if (m % i == 0) {
 ds[idx++] = i;
 while (m % i == 0) m /= i;
 }
 }
 if (m != 1) ds[idx++] = m;

 uint32_t _pr = 2;
 while (1) {
 int flg = 1;
 for (int i = 0; i < idx; ++i) {
 u64 a = _pr, b = (_mod - 1) / ds[i], r = 1;
 while (b) {
 if (b & 1) r = r * a % _mod;
 a = a * a % _mod;
 b >>= 1;
 }
 if (r == 1) {
 flg = 0;
 break;
 }
 }
 if (flg == 1) break;
 ++_pr;
 }
 return _pr;
 };

 static constexpr uint32_t mod = mint::get_mod();
 static constexpr uint32_t pr = get_pr();
 static constexpr int level = __builtin_ctzll(mod - 1);
 mint dw[level], dy[level];

 void setwy(int k) {
 mint w[level], y[level];
 w[k - 1] = mint(pr).pow((mod - 1) / (1 << k));
 y[k - 1] = w[k - 1].inverse();
 for (int i = k - 2; i > 0; --i)
 w[i] = w[i + 1] * w[i + 1], y[i] = y[i + 1] * y[i + 1];
 dw[1] = w[1], dy[1] = y[1], dw[2] = w[2], dy[2] = y[2];
 for (int i = 3; i < k; ++i) {
 dw[i] = dw[i - 1] * y[i - 2] * w[i];
 dy[i] = dy[i - 1] * w[i - 2] * y[i];
 }
 }

 NTT() { setwy(level); }

 void fft4(vector<mint> &a, int k) {
 if ((int)a.size() <= 1) return;
 if (k == 1) {
 mint a1 = a[1];
 a[1] = a[0] - a[1];
 a[0] = a[0] + a1;
 return;
 }
 if (k & 1) {
 int v = 1 << (k - 1);
 for (int j = 0; j < v; ++j) {
 mint ajv = a[j + v];
 a[j + v] = a[j] - ajv;
 a[j] += ajv;
 }
 }
 int u = 1 << (2 + (k & 1));
 int v = 1 << (k - 2 - (k & 1));
 mint one = mint(1);
 mint imag = dw[1];
 while (v) {
 
 {
 int j0 = 0;
 int j1 = v;
 int j2 = j1 + v;
 int j3 = j2 + v;
 for (; j0 < v; ++j0, ++j1, ++j2, ++j3) {
 mint t0 = a[j0], t1 = a[j1], t2 = a[j2], t3 = a[j3];
 mint t0p2 = t0 + t2, t1p3 = t1 + t3;
 mint t0m2 = t0 - t2, t1m3 = (t1 - t3) * imag;
 a[j0] = t0p2 + t1p3, a[j1] = t0p2 - t1p3;
 a[j2] = t0m2 + t1m3, a[j3] = t0m2 - t1m3;
 }
 }
 
 mint ww = one, xx = one * dw[2], wx = one;
 for (int jh = 4; jh < u;) {
 ww = xx * xx, wx = ww * xx;
 int j0 = jh * v;
 int je = j0 + v;
 int j2 = je + v;
 for (; j0 < je; ++j0, ++j2) {
 mint t0 = a[j0], t1 = a[j0 + v] * xx, t2 = a[j2] * ww,
 t3 = a[j2 + v] * wx;
 mint t0p2 = t0 + t2, t1p3 = t1 + t3;
 mint t0m2 = t0 - t2, t1m3 = (t1 - t3) * imag;
 a[j0] = t0p2 + t1p3, a[j0 + v] = t0p2 - t1p3;
 a[j2] = t0m2 + t1m3, a[j2 + v] = t0m2 - t1m3;
 }
 xx *= dw[__builtin_ctzll((jh += 4))];
 }
 u <<= 2;
 v >>= 2;
 }
 }

 void ifft4(vector<mint> &a, int k) {
 if ((int)a.size() <= 1) return;
 if (k == 1) {
 mint a1 = a[1];
 a[1] = a[0] - a[1];
 a[0] = a[0] + a1;
 return;
 }
 int u = 1 << (k - 2);
 int v = 1;
 mint one = mint(1);
 mint imag = dy[1];
 while (u) {
 
 {
 int j0 = 0;
 int j1 = v;
 int j2 = v + v;
 int j3 = j2 + v;
 for (; j0 < v; ++j0, ++j1, ++j2, ++j3) {
 mint t0 = a[j0], t1 = a[j1], t2 = a[j2], t3 = a[j3];
 mint t0p1 = t0 + t1, t2p3 = t2 + t3;
 mint t0m1 = t0 - t1, t2m3 = (t2 - t3) * imag;
 a[j0] = t0p1 + t2p3, a[j2] = t0p1 - t2p3;
 a[j1] = t0m1 + t2m3, a[j3] = t0m1 - t2m3;
 }
 }
 
 mint ww = one, xx = one * dy[2], yy = one;
 u <<= 2;
 for (int jh = 4; jh < u;) {
 ww = xx * xx, yy = xx * imag;
 int j0 = jh * v;
 int je = j0 + v;
 int j2 = je + v;
 for (; j0 < je; ++j0, ++j2) {
 mint t0 = a[j0], t1 = a[j0 + v], t2 = a[j2], t3 = a[j2 + v];
 mint t0p1 = t0 + t1, t2p3 = t2 + t3;
 mint t0m1 = (t0 - t1) * xx, t2m3 = (t2 - t3) * yy;
 a[j0] = t0p1 + t2p3, a[j2] = (t0p1 - t2p3) * ww;
 a[j0 + v] = t0m1 + t2m3, a[j2 + v] = (t0m1 - t2m3) * ww;
 }
 xx *= dy[__builtin_ctzll(jh += 4)];
 }
 u >>= 4;
 v <<= 2;
 }
 if (k & 1) {
 u = 1 << (k - 1);
 for (int j = 0; j < u; ++j) {
 mint ajv = a[j] - a[j + u];
 a[j] += a[j + u];
 a[j + u] = ajv;
 }
 }
 }

 void ntt(vector<mint> &a) {
 if ((int)a.size() <= 1) return;
 fft4(a, __builtin_ctz(a.size()));
 }

 void intt(vector<mint> &a) {
 if ((int)a.size() <= 1) return;
 ifft4(a, __builtin_ctz(a.size()));
 mint iv = mint(a.size()).inverse();
 for (auto &x : a) x *= iv;
 }

 vector<mint> multiply(const vector<mint> &a, const vector<mint> &b) {
 int l = a.size() + b.size() - 1;
 if (min<int>(a.size(), b.size()) <= 40) {
 vector<mint> s(l);
 for (int i = 0; i < (int)a.size(); ++i)
 for (int j = 0; j < (int)b.size(); ++j) s[i + j] += a[i] * b[j];
 return s;
 }
 int k = 2, M = 4;
 while (M < l) M <<= 1, ++k;
 setwy(k);
 vector<mint> s(M), t(M);
 for (int i = 0; i < (int)a.size(); ++i) s[i] = a[i];
 for (int i = 0; i < (int)b.size(); ++i) t[i] = b[i];
 fft4(s, k);
 fft4(t, k);
 for (int i = 0; i < M; ++i) s[i] *= t[i];
 ifft4(s, k);
 s.resize(l);
 mint invm = mint(M).inverse();
 for (int i = 0; i < l; ++i) s[i] *= invm;
 return s;
 }

 void ntt_doubling(vector<mint> &a) {
 int M = (int)a.size();
 auto b = a;
 intt(b);
 mint r = 1, zeta = mint(pr).pow((mint::get_mod() - 1) / (M << 1));
 for (int i = 0; i < M; i++) b[i] *= r, r *= zeta;
 ntt(b);
 copy(begin(b), end(b), back_inserter(a));
 }
};

template <typename mint>
struct FormalPowerSeries : vector<mint> {
 using vector<mint>::vector;
 using FPS = FormalPowerSeries;

 FPS &operator+=(const FPS &r) {
 if (r.size() > this->size()) this->resize(r.size());
 for (int i = 0; i < (int)r.size(); i++) (*this)[i] += r[i];
 return *this;
 }

 FPS &operator+=(const mint &r) {
 if (this->empty()) this->resize(1);
 (*this)[0] += r;
 return *this;
 }

 FPS &operator-=(const FPS &r) {
 if (r.size() > this->size()) this->resize(r.size());
 for (int i = 0; i < (int)r.size(); i++) (*this)[i] -= r[i];
 return *this;
 }

 FPS &operator-=(const mint &r) {
 if (this->empty()) this->resize(1);
 (*this)[0] -= r;
 return *this;
 }

 FPS &operator*=(const mint &v) {
 for (int k = 0; k < (int)this->size(); k++) (*this)[k] *= v;
 return *this;
 }

 FPS &operator/=(const FPS &r) {
 if (this->size() < r.size()) {
 this->clear();
 return *this;
 }
 int n = this->size() - r.size() + 1;
 if ((int)r.size() <= 64) {
 FPS f(*this), g(r);
 g.shrink();
 mint coeff = g.back().inverse();
 for (auto &x : g) x *= coeff;
 int deg = (int)f.size() - (int)g.size() + 1;
 int gs = g.size();
 FPS quo(deg);
 for (int i = deg - 1; i >= 0; i--) {
 quo[i] = f[i + gs - 1];
 for (int j = 0; j < gs; j++) f[i + j] -= quo[i] * g[j];
 }
 *this = quo * coeff;
 this->resize(n, mint(0));
 return *this;
 }
 return *this = ((*this).rev().pre(n) * r.rev().inv(n)).pre(n).rev();
 }

 FPS &operator%=(const FPS &r) {
 *this -= *this / r * r;
 shrink();
 return *this;
 }

 FPS operator+(const FPS &r) const { return FPS(*this) += r; }
 FPS operator+(const mint &v) const { return FPS(*this) += v; }
 FPS operator-(const FPS &r) const { return FPS(*this) -= r; }
 FPS operator-(const mint &v) const { return FPS(*this) -= v; }
 FPS operator*(const FPS &r) const { return FPS(*this) *= r; }
 FPS operator*(const mint &v) const { return FPS(*this) *= v; }
 FPS operator/(const FPS &r) const { return FPS(*this) /= r; }
 FPS operator%(const FPS &r) const { return FPS(*this) %= r; }
 FPS operator-() const {
 FPS ret(this->size());
 for (int i = 0; i < (int)this->size(); i++) ret[i] = -(*this)[i];
 return ret;
 }

 void shrink() {
 while (this->size() && this->back() == mint(0)) this->pop_back();
 }

 FPS rev() const {
 FPS ret(*this);
 reverse(begin(ret), end(ret));
 return ret;
 }

 FPS dot(FPS r) const {
 FPS ret(min(this->size(), r.size()));
 for (int i = 0; i < (int)ret.size(); i++) ret[i] = (*this)[i] * r[i];
 return ret;
 }

 FPS pre(int sz) const {
 return FPS(begin(*this), begin(*this) + min((int)this->size(), sz));
 }

 FPS operator>>(int sz) const {
 if ((int)this->size() <= sz) return {};
 FPS ret(*this);
 ret.erase(ret.begin(), ret.begin() + sz);
 return ret;
 }

 FPS operator<<(int sz) const {
 FPS ret(*this);
 ret.insert(ret.begin(), sz, mint(0));
 return ret;
 }

 FPS diff() const {
 const int n = (int)this->size();
 FPS ret(max(0, n - 1));
 mint one(1), coeff(1);
 for (int i = 1; i < n; i++) {
 ret[i - 1] = (*this)[i] * coeff;
 coeff += one;
 }
 return ret;
 }

 FPS integral() const {
 const int n = (int)this->size();
 FPS ret(n + 1);
 ret[0] = mint(0);
 if (n > 0) ret[1] = mint(1);
 auto mod = mint::get_mod();
 for (int i = 2; i <= n; i++) ret[i] = (-ret[mod % i]) * (mod / i);
 for (int i = 0; i < n; i++) ret[i + 1] *= (*this)[i];
 return ret;
 }

 mint eval(mint x) const {
 mint r = 0, w = 1;
 for (auto &v : *this) r += w * v, w *= x;
 return r;
 }

 FPS log(int deg = -1) const {
 assert((*this)[0] == mint(1));
 if (deg == -1) deg = (int)this->size();
 return (this->diff() * this->inv(deg)).pre(deg - 1).integral();
 }

 FPS pow(int64_t k, int deg = -1) const {
 const int n = (int)this->size();
 if (deg == -1) deg = n;
 if (k == 0) {
 FPS ret(deg);
 if (deg) ret[0] = 1;
 return ret;
 }
 for (int i = 0; i < n; i++) {
 if ((*this)[i] != mint(0)) {
 mint rev = mint(1) / (*this)[i];
 FPS ret = (((*this * rev) >> i).log(deg) * k).exp(deg);
 ret *= (*this)[i].pow(k);
 ret = (ret << (i * k)).pre(deg);
 if ((int)ret.size() < deg) ret.resize(deg, mint(0));
 return ret;
 }
 if (__int128_t(i + 1) * k >= deg) return FPS(deg, mint(0));
 }
 return FPS(deg, mint(0));
 }

 static void *ntt_ptr;
 static void set_fft();
 FPS &operator*=(const FPS &r);
 void ntt();
 void intt();
 void ntt_doubling();
 static int ntt_pr();
 FPS inv(int deg = -1) const;
 FPS exp(int deg = -1) const;
};
template <typename mint>
void *FormalPowerSeries<mint>::ntt_ptr = nullptr;






template <typename mint>
void FormalPowerSeries<mint>::set_fft() {
 if (!ntt_ptr) ntt_ptr = new NTT<mint>;
}

template <typename mint>
FormalPowerSeries<mint>& FormalPowerSeries<mint>::operator*=(
 const FormalPowerSeries<mint>& r) {
 if (this->empty() || r.empty()) {
 this->clear();
 return *this;
 }
 set_fft();
 auto ret = static_cast<NTT<mint>*>(ntt_ptr)->multiply(*this, r);
 return *this = FormalPowerSeries<mint>(ret.begin(), ret.end());
}

template <typename mint>
void FormalPowerSeries<mint>::ntt() {
 set_fft();
 static_cast<NTT<mint>*>(ntt_ptr)->ntt(*this);
}

template <typename mint>
void FormalPowerSeries<mint>::intt() {
 set_fft();
 static_cast<NTT<mint>*>(ntt_ptr)->intt(*this);
}

template <typename mint>
void FormalPowerSeries<mint>::ntt_doubling() {
 set_fft();
 static_cast<NTT<mint>*>(ntt_ptr)->ntt_doubling(*this);
}

template <typename mint>
int FormalPowerSeries<mint>::ntt_pr() {
 set_fft();
 return static_cast<NTT<mint>*>(ntt_ptr)->pr;
}

template <typename mint>
FormalPowerSeries<mint> FormalPowerSeries<mint>::inv(int deg) const {
 assert((*this)[0] != mint(0));
 if (deg == -1) deg = (int)this->size();
 FormalPowerSeries<mint> res(deg);
 res[0] = {mint(1) / (*this)[0]};
 for (int d = 1; d < deg; d <<= 1) {
 FormalPowerSeries<mint> f(2 * d), g(2 * d);
 for (int j = 0; j < min((int)this->size(), 2 * d); j++) f[j] = (*this)[j];
 for (int j = 0; j < d; j++) g[j] = res[j];
 f.ntt();
 g.ntt();
 for (int j = 0; j < 2 * d; j++) f[j] *= g[j];
 f.intt();
 for (int j = 0; j < d; j++) f[j] = 0;
 f.ntt();
 for (int j = 0; j < 2 * d; j++) f[j] *= g[j];
 f.intt();
 for (int j = d; j < min(2 * d, deg); j++) res[j] = -f[j];
 }
 return res.pre(deg);
}

template <typename mint>
FormalPowerSeries<mint> FormalPowerSeries<mint>::exp(int deg) const {
 using fps = FormalPowerSeries<mint>;
 assert((*this).size() == 0 || (*this)[0] == mint(0));
 if (deg == -1) deg = this->size();

 fps inv;
 inv.reserve(deg + 1);
 inv.push_back(mint(0));
 inv.push_back(mint(1));

 auto inplace_integral = [&](fps& F) -> void {
 const int n = (int)F.size();
 auto mod = mint::get_mod();
 while ((int)inv.size() <= n) {
 int i = inv.size();
 inv.push_back((-inv[mod % i]) * (mod / i));
 }
 F.insert(begin(F), mint(0));
 for (int i = 1; i <= n; i++) F[i] *= inv[i];
 };

 auto inplace_diff = [](fps& F) -> void {
 if (F.empty()) return;
 F.erase(begin(F));
 mint coeff = 1, one = 1;
 for (int i = 0; i < (int)F.size(); i++) {
 F[i] *= coeff;
 coeff += one;
 }
 };

 fps b{1, 1 < (int)this->size() ? (*this)[1] : 0}, c{1}, z1, z2{1, 1};
 for (int m = 2; m < deg; m *= 2) {
 auto y = b;
 y.resize(2 * m);
 y.ntt();
 z1 = z2;
 fps z(m);
 for (int i = 0; i < m; ++i) z[i] = y[i] * z1[i];
 z.intt();
 fill(begin(z), begin(z) + m / 2, mint(0));
 z.ntt();
 for (int i = 0; i < m; ++i) z[i] *= -z1[i];
 z.intt();
 c.insert(end(c), begin(z) + m / 2, end(z));
 z2 = c;
 z2.resize(2 * m);
 z2.ntt();
 fps x(begin(*this), begin(*this) + min<int>(this->size(), m));
 x.resize(m);
 inplace_diff(x);
 x.push_back(mint(0));
 x.ntt();
 for (int i = 0; i < m; ++i) x[i] *= y[i];
 x.intt();
 x -= b.diff();
 x.resize(2 * m);
 for (int i = 0; i < m - 1; ++i) x[m + i] = x[i], x[i] = mint(0);
 x.ntt();
 for (int i = 0; i < 2 * m; ++i) x[i] *= z2[i];
 x.intt();
 x.pop_back();
 inplace_integral(x);
 for (int i = m; i < min<int>(this->size(), 2 * m); ++i) x[i] += (*this)[i];
 fill(begin(x), begin(x) + m, mint(0));
 x.ntt();
 for (int i = 0; i < 2 * m; ++i) x[i] *= y[i];
 x.intt();
 b.insert(end(b), begin(x) + m, end(x));
 }
 return fps{begin(b), begin(b) + deg};
}









template <uint32_t mod>
struct LazyMontgomeryModInt {
 using mint = LazyMontgomeryModInt;
 using i32 = int32_t;
 using u32 = uint32_t;
 using u64 = uint64_t;

 static constexpr u32 get_r() {
 u32 ret = mod;
 for (i32 i = 0; i < 4; ++i) ret *= 2 - mod * ret;
 return ret;
 }

 static constexpr u32 r = get_r();
 static constexpr u32 n2 = -u64(mod) % mod;
 static_assert(r * mod == 1, "invalid, r * mod != 1");
 static_assert(mod < (1 << 30), "invalid, mod >= 2 ^ 30");
 static_assert((mod & 1) == 1, "invalid, mod % 2 == 0");

 u32 a;

 constexpr LazyMontgomeryModInt() : a(0) {}
 constexpr LazyMontgomeryModInt(const int64_t &b)
 : a(reduce(u64(b % mod + mod) * n2)){};

 static constexpr u32 reduce(const u64 &b) {
 return (b + u64(u32(b) * u32(-r)) * mod) >> 32;
 }

 constexpr mint &operator+=(const mint &b) {
 if (i32(a += b.a - 2 * mod) < 0) a += 2 * mod;
 return *this;
 }

 constexpr mint &operator-=(const mint &b) {
 if (i32(a -= b.a) < 0) a += 2 * mod;
 return *this;
 }

 constexpr mint &operator*=(const mint &b) {
 a = reduce(u64(a) * b.a);
 return *this;
 }

 constexpr mint &operator/=(const mint &b) {
 *this *= b.inverse();
 return *this;
 }

 constexpr mint operator+(const mint &b) const { return mint(*this) += b; }
 constexpr mint operator-(const mint &b) const { return mint(*this) -= b; }
 constexpr mint operator*(const mint &b) const { return mint(*this) *= b; }
 constexpr mint operator/(const mint &b) const { return mint(*this) /= b; }
 constexpr bool operator==(const mint &b) const {
 return (a >= mod ? a - mod : a) == (b.a >= mod ? b.a - mod : b.a);
 }
 constexpr bool operator!=(const mint &b) const {
 return (a >= mod ? a - mod : a) != (b.a >= mod ? b.a - mod : b.a);
 }
 constexpr mint operator-() const { return mint() - mint(*this); }

 constexpr mint pow(u64 n) const {
 mint ret(1), mul(*this);
 while (n > 0) {
 if (n & 1) ret *= mul;
 mul *= mul;
 n >>= 1;
 }
 return ret;
 }
 
 constexpr mint inverse() const { return pow(mod - 2); }

 friend ostream &operator<<(ostream &os, const mint &b) {
 return os << b.get();
 }

 friend istream &operator>>(istream &is, mint &b) {
 int64_t t;
 is >> t;
 b = LazyMontgomeryModInt<mod>(t);
 return (is);
 }
 
 constexpr u32 get() const {
 u32 ret = reduce(a);
 return ret >= mod ? ret - mod : ret;
 }

 static constexpr u32 get_mod() { return mod; }
};

template <typename T>
struct Binomial {
 vector<T> f, g, h;
 Binomial(int MAX = 0) {
 assert(T::get_mod() != 0 && "Binomial<mint>()");
 f.resize(1, T{1});
 g.resize(1, T{1});
 h.resize(1, T{1});
 while (MAX >= (int)f.size()) extend();
 }

 void extend() {
 int n = f.size();
 int m = n * 2;
 f.resize(m);
 g.resize(m);
 h.resize(m);
 for (int i = n; i < m; i++) f[i] = f[i - 1] * T(i);
 g[m - 1] = f[m - 1].inverse();
 h[m - 1] = g[m - 1] * f[m - 2];
 for (int i = m - 2; i >= n; i--) {
 g[i] = g[i + 1] * T(i + 1);
 h[i] = g[i] * f[i - 1];
 }
 }

 T fac(int i) {
 if (i < 0) return T(0);
 while (i >= (int)f.size()) extend();
 return f[i];
 }

 T finv(int i) {
 if (i < 0) return T(0);
 while (i >= (int)g.size()) extend();
 return g[i];
 }

 T inv(int i) {
 if (i < 0) return -inv(-i);
 while (i >= (int)h.size()) extend();
 return h[i];
 }

 T C(int n, int r) {
 if (n < 0 || n < r || r < 0) return T(0);
 return fac(n) * finv(n - r) * finv(r);
 }

 inline T operator()(int n, int r) { return C(n, r); }

 template <typename I>
 T multinomial(const vector<I>& r) {
 static_assert(is_integral<I>::value == true);
 int n = 0;
 for (auto& x : r) {
 if (x < 0) return T(0);
 n += x;
 }
 T res = fac(n);
 for (auto& x : r) res *= finv(x);
 return res;
 }

 template <typename I>
 T operator()(const vector<I>& r) {
 return multinomial(r);
 }

 T C_naive(int n, int r) {
 if (n < 0 || n < r || r < 0) return T(0);
 T ret = T(1);
 r = min(r, n - r);
 for (int i = 1; i <= r; ++i) ret *= inv(i) * (n--);
 return ret;
 }

 T P(int n, int r) {
 if (n < 0 || n < r || r < 0) return T(0);
 return fac(n) * finv(n - r);
 }

 
 T H(int n, int r) {
 if (n < 0 || r < 0) return T(0);
 return r == 0 ? 1 : C(n + r - 1, r);
 }
};



template <typename mint>
FormalPowerSeries<mint> Pi(vector<FormalPowerSeries<mint>> v) {
 using fps = FormalPowerSeries<mint>;
 if ((int)v.size() == 0) return fps{mint(1)};
 sort(begin(v), end(v), [](fps& a, fps& b) { return a.size() < b.size(); });
 queue<fps> q;
 for (auto& f : v) q.push(f);
 while ((int)q.size() > 1) {
 fps a = q.front();
 q.pop();
 fps b = q.front();
 q.pop();
 q.push(a * b);
 }
 return q.front();
}

template <typename mint>
void OGFtoEGF(FormalPowerSeries<mint>& f, Binomial<mint>& C) {
 for (int i = 0; i < (int)f.size(); i++) f[i] *= C.finv(i);
}

template <typename mint>
void EGFtoOGF(FormalPowerSeries<mint>& f, Binomial<mint>& C) {
 for (int i = 0; i < (int)f.size(); i++) f[i] *= C.fac(i);
}

template <typename mint>
FormalPowerSeries<mint> e_x(int deg, Binomial<mint>& C) {
 while ((int)C.g.size() < deg) C.extend();
 FormalPowerSeries<mint> ret{begin(C.g), begin(C.g) + deg};
 return ret;
}


template <typename mint>
void sparse_mul(FormalPowerSeries<mint>& f, int n, mint c, int expand = true) {
 if (expand) f.resize(f.size() + n);
 for (int i = (int)f.size() - 1; i >= 0; --i) {
 if (i - n >= 0) f[i] += f[i - n] * c;
 }
}


template <typename mint>
void sparse_div(FormalPowerSeries<mint>& f, int n, mint c) {
 for (int i = 0; i < (int)f.size(); ++i) {
 if (i + n < (int)f.size()) f[i + n] -= f[i] * c;
 }
}



using namespace Nyaan;
using mint = LazyMontgomeryModInt<998244353>;

using vm = vector<mint>;
using vvm = vector<vm>;
Binomial<mint> C;
using fps = FormalPowerSeries<mint>;

using namespace Nyaan;

void q() {
 inl(N, M);
 vl A(N), B(N);
 in(A, B);
 V<fps> fs;
 rep(i, N) {
 fps f(A[i] + 1);
 mint coeff = 1;
 reg(j, 0, B[i]) {
 f[j] = C.finv(j) * coeff;
 coeff *= mint{A[i] - j};
 }
 fs.push_back(f);
 }

 fps D(M);
 rep(i, M) D[i] = C(M - 1, i).inverse() * C.fac(M - 1);

 V<pl> qs;
 rep(i, N) qs.push_back(pl{M - B[i], i});
 sort(all(qs));
 vm ans(N);

 int X = 1;
 while (X < N) X *= 2;

 V<fps> mod(2 * X, fps{1});
 vi mn(2 * X, M), mx(2 * X, M);
 rep(i, N) {
 mod[X + i] = fs[qs[i].se];
 mn[X + i] = mx[X + i] = qs[i].fi;
 }
 for (int i = X - 1; i > 0; i--) {
 mod[i] = mod[2 * i] * mod[2 * i + 1];
 mn[i] = mn[2 * i];
 mx[i] = mx[2 * i + 1];
 }

 auto dc = [&](auto rc, int idx, int l, int r, int of, fps f) -> void {
 trc(idx, l, r, of, sz(f));
 if (N <= l) return;
 
 
 int cmn = min<int>(mn[idx], mx[idx] - sz(mod[idx]));
 if (cmn < 0) cmn = 0;
 int cmx = mx[idx] + 1;
 trc(cmn, cmx);
 if (of < cmn) {
 f.erase(begin(f), begin(f) + (cmn - of));
 of = cmn;
 }
 f.resize(cmx - cmn);
 if (l + 1 == r) {
 ans[qs[l].se] = f[qs[l].fi - of];
 return;
 }
 int m = (l + r) / 2;
 rc(rc, idx * 2 + 0, l, m, of, f * mod[2 * idx + 1]);
 rc(rc, idx * 2 + 1, m, r, of, f * mod[2 * idx + 0]);
 };
 dc(dc, 1, 0, X, 0, D);
 







 rep(i, N) { out(ans[i] * C(A[i], B[i]) * B[i]); }
}

void Nyaan::solve() {
 int t = 1;
 
 while (t--) q();
}
accuracy: 1
time_ms: 560
memory_kb: 76328
final_rank: 3

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

template <class T> void pv(T a, T b) {
  for (T i = a; i != b; ++i) cerr << *i << " ";
  cerr << endl;
}
template <class T1, class T2> ostream &operator<<(ostream &os, const pair<T1, T2> &p) {
  return os << "(" << p.first << ", " << p.second << ")";
}

// maroon shakyou-modint
using ll=long long;
const uint mod=998244353;
struct mint{
  uint v;
  mint(ll vv=0){s(vv%mod+mod);}
  mint& s(uint vv){
    v=vv<mod?vv:vv-mod;
    return *this;
  }
  mint operator-()const{return mint()-*this;}
  mint&operator+=(mint r){return s(v+r.v);}
  mint&operator-=(mint r){return s(v+mod-r.v);}
  mint&operator*=(mint r){v=(unsigned ll)v*r.v%mod;return *this;}
  mint&operator/=(mint r){return *this*=r.inv();}
  mint operator+(mint r)const{return mint(*this)+=r;}
  mint operator-(mint r)const{return mint(*this)-=r;}
  mint operator*(mint r)const{return mint(*this)*=r;}
  mint operator/(mint r)const{return mint(*this)/=r;}
  mint pow(ll n)const{
    if(n<0)return inv().pow(-n);
    mint res(1),x(*this);
    while(n){
      if(n&1)res*=x;
      x*=x;
      n>>=1;
    }
    return res;
  }
  mint inv()const{return pow(mod-2);}
};

ostream &operator<<(ostream &os, mint a) {
  return os << a.v;
}

// maroon shakyou-fmt
const mint prim_root=3;
const mint prim_root_inv=prim_root.inv();
void inplace_fmt(vector<mint>&f, const bool inv){
  const int n = f.size();
  const mint root = inv?prim_root_inv:prim_root;
  static vector<mint>g;
  g.clear();g.resize(n);
  
  for(int b=n/2;b>=1;b/=2){
    mint w=root.pow((mod-1)/(n/b)), p = 1;
    for(int i=0;i<n;i+=b*2){
      for(int j=0;j<b;++j){
        f[i+j+b]*=p;
        g[i/2+j]=f[i+j]+f[i+b+j];
        g[n/2+i/2+j]=f[i+j]-f[i+b+j];
      }
      p*=w;
    }
    swap(f, g);
  }
  if(inv){
    mint z=mint(n).inv();
    for(int i=0;i<n;++i)f[i]*=z;
  }
}
vector<mint> multiply(vector<mint> a,vector<mint> b){
  int n=a.size(),m=b.size();
  assert(n>0&&m>0);
  int s=1;while(s<n+m-1)s*=2;
  a.resize(s);inplace_fmt(a,false);
  b.resize(s);inplace_fmt(b,false);
  for(int i=0;i<s;++i)a[i]*=b[i];inplace_fmt(a,true);
  a.resize(n+m-1);return a;
}


vector<mint> middle(vector<mint> as, vector<mint> bs) {
  const int m = as.size();
  const int n = bs.size();
  assert(m <= n);
  int nn = 1;
  for (; nn < n; nn <<= 1) {}
  reverse(as.begin(), as.end());
  as.resize(nn, 0);
  inplace_fmt(as, false);
  bs.resize(nn, 0);
  inplace_fmt(bs, false);
  for (int i = 0; i < nn; ++i) {
    bs[i] *= as[i];
  }
  inplace_fmt(bs, true);
  bs.resize(n);
  bs.erase(bs.begin(), bs.begin() + (m - 1));
  return bs;
}


constexpr int LIM = 400'010;
mint inv[LIM], fac[LIM], invFac[LIM];

int N, M;
vector<int> A, B;

vector<int> BL, BR;
vector<vector<mint>> FL, FR;
pair<int, vector<mint>> dfs(int l, int r) {
  pair<int, vector<mint>> ret;
  if (l + 1 == r) {
    const int i = l;
    ret.first = B[i];
    ret.second.resize(B[i]);
    for (int j = 0; j < B[i]; ++j) {
      ret.second[j] = invFac[j] * invFac[A[i] - j];
    }
  } else {
    const int mid = (l + r) / 2;
    const auto resL = dfs(l, mid);
    const auto resR = dfs(mid, r);
    BL[mid] = resL.first; FL[mid] = resL.second;
    BR[mid] = resR.first; FR[mid] = resR.second;
    ret.first = resL.first + resR.first;
    ret.second = multiply(resL.second, resR.second);
  }
  return ret;
}

vector<mint> ans;
void DFS(int l, int r, const vector<mint> &ps) {
  if (l + 1 == r) {
    const int i = l;
    ans[i] = invFac[B[i] - 1] * invFac[A[i] - B[i]] * ps[B[i] - 1];
  } else {
    const int mid = (l + r) / 2;
    auto psL = middle(FR[mid], ps);
    auto psR = middle(FL[mid], ps);
    assert((int)psL.size() >= BL[mid]);
    assert((int)psR.size() >= BR[mid]);
    psL.resize(BL[mid]);
    psR.resize(BR[mid]);
    DFS(l, mid, psL);
    DFS(mid, r, psR);
  }
}

int main() {
  inv[1] = 1;
  for (int i = 2; i < LIM; ++i) {
    inv[i] = -mint(mod / i) * inv[mod % i];
  }
  fac[0] = invFac[0] = 1;
  for (int i = 1; i < LIM; ++i) {
    fac[i] = fac[i - 1] * i;
    invFac[i] = invFac[i - 1] * inv[i];
  }
#ifdef LOCAL
pv(inv,inv+10);
pv(fac,fac+10);
pv(invFac,invFac+10);
vector<mint>as{1,2,3},bs{4,5};
const auto cs=multiply(as,bs);
pv(cs.begin(),cs.end());
cerr<<"========"<<endl;
#endif
  
  for (; ~scanf("%d%d", &N, &M); ) {
    A.resize(N); for (int i = 0; i < N; ++i) scanf("%d", &A[i]);
    B.resize(N); for (int i = 0; i < N; ++i) scanf("%d", &B[i]);
    
    BL.resize(N); FL.resize(N);
    BR.resize(N); FR.resize(N);
    const auto res = dfs(0, N);
    ans.resize(N);
    vector<mint> ini(res.first);
    for (int j = 0; j < res.first; ++j) {
      ini[j] = fac[j] * fac[M - 1 - j];
    }
    DFS(0, N, ini);
    
    mint coef = 1;
    for (int i = 0; i < N; ++i) {
      coef *= fac[A[i]];
    }
    for (int i = 0; i < N; ++i) {
      ans[i] *= coef;
      printf("%u\n", ans[i].v);
    }
#ifdef LOCAL
cerr<<"========"<<endl;
#endif
  }
  return 0;
}
accuracy: 1
time_ms: 680
memory_kb: 43320
final_rank: 1