闲话 23.1.25

闲话

今天这题听说可以容斥系数转生成函数做?
感觉类似这个的做法
然而不会欸

话说青猪的小说我之前也看过一些
但是看完前三卷就没想着往下看了(
现在回想起来也不知道是为啥了
但是番剧都看完了 好看的 推荐

今日推歌:笠泽之畔 - Sodatune with 洛天依

杂题

[集训队作业2019] 青春猪头少年不会梦到兔女郎学姐

若干个正整数排成一个序列,其中数字 \(i\) 的出现次数为 \(r_i\),对于每一个这样的序列,定义他的权值如下:

把这个序列首尾相接放在一个圆上,把这些数字分成若干相邻的段,使得每段都是在圆上相邻的数字,任意两段没有公共的元素,每一段中的数字都相同,相邻段中的数字不同,则这个序列的权值定义为所有段的长度之积。

求所有的序列的权值和对 \(998244353\) 取模。

注:虽然计算序列的权值的时候是圆排列,但互为循环排列的不同序列仍然被认为是不同的,如 \((1,2,1,2)\)\((2,1,2,1)\) 被认为是不同的序列。

\(2\le n, \sum c_i \le 2\times 10^5\)

之前做 CF840C 的时候就想写来着,但是当时统计的是方案数,所以和答案一直对不上。遂弃之。
模拟赛考了,所以考虑写一份。任意模数可以采用 MTT,不是重点。
\(m = \sum c_i\)

首先考虑序列问题如何计算。

承接先前的思路,我们考虑一个容斥。这里写出的式子和之前形式不是很相同,这是由于本题需要的式子分析能力更高,换个写法更容易看出来。

应用容斥后我们就需要计算不考虑限制的情况下的贡献如何计算,也就是将长度为 \(n\) 的序列任意分为 \(m\) 段,每一段长度乘积之和。
可以发现长度乘积本质上就是分割后从每一段中选择一个值的方案数,因此考虑插板法刻画。我们在序列中插入 \(m - 1\) 块板,并在这些板分割的 \(m\) 段中各选一个。这也就是从 \(n + m - 1\) 个元素中选择 \(2m - 1\) 个,然后按照 \(被选元素-板子-被选元素-\cdots-板子-被选元素\) 的方式分配,容易发现一种选择方案能且仅能导出一种分割+选择方案,因此有双射。
这部分的答案就是 \(f(n, m) = \dbinom{n + m - 1}{2m - 1}\)

我们枚举序列 \(\langle a\rangle\),意义是将颜色 \(i\) 任意分为 \(a_i\) 段。然后再枚举序列 \(\langle c\rangle\),意义是颜色 \(i\) 被缩成的段数。
可以写出

\[\sum_{a}\sum_{c} \frac{\left(\sum c_i\right)!}{\prod c_i!} \prod_{i = 1}^n (-1)^{a_i - c_i} f(r_i, a_i) \binom{a_i - 1}{c_i - 1} \]

发现 \(\dfrac{\left(\sum c_i\right)!}{\prod c_i!}\) 的部分是一个多重集组合数的形式,这个东西可以通过为每个元素分别构造 egf 后卷积起来构造。因此不妨构造生成函数,占位元是 \(k_{c_i}(x) = \dfrac{x^{c_i}}{c_i!}\) 来刻画性质。这样我们首先需要的是将 \(c\) 提前,也就是

\[\sum_{c} \left(\sum c_i\right)! \sum_{\forall c_i\le a_i \le r_i} \prod_{i = 1}^n (-1)^{a_i - c_i} f(r_i, a_i) \binom{a_i - 1}{c_i - 1}\frac{1}{c_i!} \]

这个形式可以构造生成函数来枚举 \(k = c_i\),第 \(i\) 种颜色对应的 egf 就是

\[F_i(x) = \sum_{k = 1}^{r_i} \sum_{k\le a_i \le r_i} (-1)^{a_i - k} f(r_i, a_i) \binom{a_i - 1}{k - 1}\frac{x^k}{k!} \]

这个东西可以构造卷积后取后 \(r_i + 1\) 项得到。构造部分的总时间复杂度是 \(O(m\log m)\) 的。

iostream 说把上面的东西乘起来得到 \(F\)\(m\sum_{i = 1}^{m} (i - 1)! [x^i]F(x)\) 就是答案,这确实。
具体为啥他不知道,我也不太知道。有懂的读者可以在评论区给讲讲。

然后考虑如何把序列问题的解法转到环上。

我们钦定颜色 \(1\) 其中一段段首为整个环的起始位置。然后删掉结尾也是一段 \(1\) 的情况。这等于是钦定了一段/两段是颜色 \(1\)。可以发现我们只需要把 egf \(F_1(x)\) 的系数向左平移 \(1, 2\) 就能得到答案了。这里注意不要把 \(k\) 次项里的 \(\dfrac{1}{k!}\) 也左移,这就需要我们首先用 ogf 的方式存储 \(F\)
具体地,首先计算颜色 \(2\sim n\) 的 egf 的乘积 \(F'\),然后用 \(F_1\) 左移 \(1\) 位得到的多项式乘 \(F'\),再减去 \(F_1\) 左移 \(2\) 位得到的多项式乘 \(F'\) 的结果,得到最终多项式 \(F_{end}\),设 \(ans = \sum_{k \ge 0} [x^k/k!] F_{end}\)
\(F_{end}\) 的求得可以 \(O(m\log^2 m)\) 地做到。

\(ans\) 不是最终答案。
如果 \(1\) 颜色出现了 \(k\) 次,我们就会老老实实数 \(k\) 次,这是不行的,因此最开始的 \([x^k]F_1\) 得先除一个 \(k\)
题目中要求每个循环移位作为不同情况出现,因此一个环的贡献要乘以循环节长度。然而按上面的做法没有考虑循环节,因此乘入 \(m\) 即可考虑循环节数量,并乘入了循环节长度作为贡献。

这样我们就在 \(O(m\log^2 m)\) 的复杂度内得到了答案。

code(iostream 的奇妙做法)
#include <bits/stdc++.h>
using namespace std; 
using pii = pair<int,int>; using vi = vector<int>; using vp = vector<pii>; using ll = long long; 
using ull = unsigned long long; using db = double; using ld = long double; using lll = __int128_t;
template<typename T1, typename T2> T1 max(T1 a, T2 b) { return a > b ? a : b; }
template<typename T1, typename T2> T1 min(T1 a, T2 b) { return a < b ? a : b; }
#define multi int T; cin >> T; while ( T -- )
#define timer cerr << 1. * clock() / CLOCKS_PER_SEC << '\n';
#define iot ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define file(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define rep(i,s,t) for (register int i = (s), i##_ = (t) + 1; i < i##_; ++ i)
#define pre(i,s,t) for (register int i = (s), i##_ = (t) - 1; i > i##_; -- i)
#define eb emplace_back
#define pb pop_back
const int N = 1e6 + 10;
const int inf = 0x3f3f3f3f;
const ll infll = 0x3f3f3f3f3f3f3f3fll;

// int mod;
// const int mod = 10007;
// const int mod = 469762049, g = 3;
const int mod = 998244353; // const int g = 3;
// const int mod = 1004535809, g = 3;
// const int mod = 1e9 + 7;
// const int mod = 1e9 + 9;
// const int mod = 1e9 + 3579, bse = 131;
/* add / sub */ 			template<typename T1,typename T2>T1 add(T1 a,T2 b){return(a+=b)>=mod?a-mod:a;}template<typename T1,typename...Args>T1 add(T1 a,Args...b){return add(a,add(b...));}template<typename T1,typename T2>T1 sub(T1 a,T2 b){return(a-=b)<0?a+mod:a;}template<typename T1,typename...Args>T1 sub(T1 a,Args...b){return sub(a,add(b...));}template<typename T1,typename T2>void addi(T1&a,T2 b){(a+=b)>=mod?(a-=mod):true;}template<typename T1,typename...Args>void addi(T1&a,Args...b){addi(a,add(b...));}template<typename T1,typename T2>void subi(T1&a,T2 b){(a-=b)<0?(a+=mod):true;}template<typename T1,typename...Args>void subi(T1&a,Args...b){subi(a,add(b...));}
/* Fastmod / mul */ 		struct FastMod{int m;ll b;void init(int _m){m=_m;if(m==0)m=1;b=((lll)1<<64)/m;}FastMod(int _m){init(_m);}int operator()(ll a){ll q=((lll)a*b)>>64;a-=q*m;if(a>=m)a-=m;return a;}}Mod(mod);int mul(int a,int b){return Mod(1ll*a*b);}template<typename T1,typename T2>int mul(T1 a,T2 b){return Mod((long long)(1ll*a*b));}template<typename T,typename...Args>int mul(T a,Args...b){return mul(a,mul(b...));}template<typename T1,typename T2>void muli(T1&a,T2 b){a=Mod(1ll*a*b);}template<typename T1,typename...Args>void muli(T1&a,Args...b){muli(a,mul(b...));} // /* trivial multiple function(idk whether its useful*/ int mul(int a, int b) { return 1ll * a * b % mod; } template <typename T1, typename T2> int mul(T1 a, T2 b) { return (long long)(1ll * a * b) % mod; } template <typename T, typename ...Args> int mul(T a, Args ...b) { return mul(a, mul(b...)); }
/* qp fac C */              template<typename T1,typename T2>T1 qp(T1 a,T2 b){T1 ret=1;for(;b>0;a=1ll*a*a%mod,b>>=1)if(b&1)ret=mul(ret,a);return ret;}vi __fac({1,1}),__ifc({1,1}),__inv({0,1});inline void ___prep(int n){static int i=2;if(i<n)for(__fac.resize(n),__ifc.resize(n),__inv.resize(n);i<n;i++)__fac[i]=mul(i,__fac[i-1]),__inv[i]=mul((mod-mod/i),__inv[mod%i]),__ifc[i]=mul(__inv[i],__ifc[i-1]);}inline int fac(int x){return ___prep(x+1),__fac[x];}inline int ifc(int x){return ___prep(x+1),__ifc[x];}inline int inv(int x){return ___prep(x+1),__inv[x];}inline int C(int n,int m){if(n<m or n<0 or m<0)return 0;return mul(fac(n),ifc(m),ifc(n-m));}
/* sum of i^k */            int S(int n,int k){vector<int>__pre(k+4),__suf(k+4),__pw(k+4),__pri(k+4);vector<bool>__vis(k+4,0);__pw[1]=1;for(int i=2,cnt=0;i<=k+2;++i){if(!__vis[i])__pri[++cnt]=i,__pw[i]=qp(i,k);for(int j=1;j<=cnt and i*__pri[j]<=k+2;++j){__vis[i*__pri[j]]=1;__pw[i*__pri[j]]=mul(__pw[i],__pw[__pri[j]]);if(i%__pri[j]==0)break;}}rep(i,2,k+2)__pw[i]=add(__pw[i],__pw[i-1]);__pre[0]=__suf[k+3]=1;rep(i,1,k+2)__pre[i]=mul(__pre[i-1],(n-i+mod));pre(i,k+2,1)__suf[i]=mul(__suf[i+1],(n-i+mod));int tmp=0,ret=0;rep(i,1,k+2){if((k-i)&1)subi(ret,mul(__pw[i],__pre[i-1],__suf[i+1],ifc(i-1),ifc(k+2-i)));else addi(ret,mul(__pw[i],__pre[i-1],__suf[i+1],ifc(i-1),ifc(k+2-i)));}return ret;}
// /* inv 2/3/6 / phi */ 		constexpr int __var_pow(int a, int b) { int ret = 1; for (; b > 0; b >>= 1, a = 1ll * a * a % mod) if (b & 1) ret = 1ll * ret * a % mod; return ret; } constexpr int __var_phi(int x) { if (x <= 2) return 1; int ret = x; for (int i = 2; 1ll * i * i <= x; ++i)  if (x % i == 0) { ret = ret / i * (i - 1); while (x % i == 0) x /= i; } if (x > 1) ret = ret / x * (x - 1); return ret; } const int __phi_mod = __var_phi(mod); const int inv2 = __var_pow(2, __phi_mod - 1), inv3 = __var_pow(3, __phi_mod - 1), inv6 = __var_pow(6, __phi_mod - 1);

int qp(int a, int b = mod - 2, int p = mod) {
	int ret = 1;
	while (b) {
		if (b & 1) ret = 1ll * ret * a % p;
		a = 1ll * a * a % p;
		b >>= 1;
	} return ret;
}

using db = double;
struct cp {
    db x, y;
    cp(db real = 0, db imag = 0) : x(real), y(imag){};
    cp operator+(cp b) const { return {x + b.x, y + b.y}; }
    cp operator-(cp b) const { return {x - b.x, y - b.y}; }
    cp operator*(cp b) const { return {x * b.x - y * b.y, x * b.y + y * b.x}; }
};
using vcp = vector<cp>;
namespace FFT {
    const db pi = acos(-1);
    vcp Omega(int L) {
        vcp w(L); w[1] = 1;
        for (register int i = 2; i < L; i <<= 1) {
            auto w0 = w.begin() + i / 2, w1 = w.begin() + i;
            cp wn(cos(pi / i), sin(pi / i));
            for (register int j = 0; j < i; j += 2)
                w1[j] = w0[j >> 1], w1[j + 1] = w1[j] * wn;
        } return w;
    } auto W = Omega(1 << 21);

    void DIF(cp *a, int n) {
        cp x, y;
        for (register int k = n >> 1; k; k >>= 1)
            for (register int i = 0; i < n; i += k << 1)
                for (register int j = 0; j < k; ++j)
                    x = a[i + j], y = a[i + j + k],
                    a[i + j + k] = (x - y) *  W[k + j], a[i + j] = x + y;
    }
    void IDIT(cp *a, int n) {
        cp x, y;
        for (register int k = 1; k < n; k <<= 1)
            for (register int i = 0; i < n; i += k << 1)
                for (register int j = 0; j < k; ++j)
                    x = a[i + j], y = a[i + j + k] * W[k + j],
                    a[i + j + k] = x - y, a[i + j] = x + y;
        const db Inv = 1. / n;
        rep(i, 0, n - 1) a[i].x *= Inv, a[i].y *= Inv;
        reverse(a + 1, a + n);
    }
} 
namespace Polynomial {
    using poly = vector<int>;

    void DFT(vcp &a) { FFT::DIF(a.data(), a.size()); }
    void IDFT(vcp &a) { FFT::IDIT(a.data(), a.size()); }
    int norm(int n) { return 1 << (__lg(n - 1) + 1); }

    poly conv(const poly &a, const poly &b, const int&P = mod) {
        
        int n = a.size(), m = b.size(), o = n + m - 1, l = norm(o);
        vcp A(l), B(l), c0(l), c1(l);
        for (register int i = 0; i < n; i++) A[i] = cp(a[i] & 0x7fff, a[i] >> 15);
        for (register int i = 0; i < m; i++) B[i] = cp(b[i] & 0x7fff, b[i] >> 15);
        FFT::DIF(A.data(), l), FFT::DIF(B.data(), l);
        for (register int k = 1, i = 0, j; k < l; k <<= 1)
            for ( ; i < k * 2; i++) {
                j = i ^ k - 1;
                c0[i] = cp(A[i].x + A[j].x, A[i].y - A[j].y) * B[i] * 0.5;
                c1[i] = cp(A[i].y + A[j].y, -A[i].x + A[j].x) * B[i] * 0.5;
            }
        FFT::IDIT(c0.data(), l), FFT::IDIT(c1.data(), l);
        poly res(o);
        for (register int i = 0; i < o; i++) {
            ll c00 = c0[i].x + 0.5, c01 = c0[i].y + 0.5, c10 = c1[i].x + 0.5, c11 = c1[i].y + 0.5;
            res[i] = (c00 + ((c01 + c10) % P << 15) + (c11 % P << 30)) % P;
        }
        return res;
    }

    poly shiftcoeff(const poly& f, const int& w = 1) {
        if (w + 1 > f.size()) return poly();
        poly ret((int)f.size() - w);
        if (ret.size() == 0) return ret;
        for (int i = w; i < f.size(); ++ i)
            ret[i - w] = f[i];
        return ret;
    }
    poly toEGF(const poly& f, const int P = mod) {
        poly ret(f);
        for (int i = 0; i < ret.size(); ++ i) 
            ret[i] = 1ll * ret[i] * ifc(i) % P;
        return ret;
    }
} using namespace Polynomial;

int n, m, r[N];
poly F[N], t1, t2;
poly dac(int l, int r) {
    if (l == r) return toEGF(F[l]);
    int mid = l + r >> 1;
    return conv(dac(l, mid), dac(mid + 1, r));
}

signed main() {
	cin >> n; rep(i,1,n) cin >> r[i];
    rep(i,1,n) {
        m += r[i]; t1.clear(), t2.clear();
        t1.resize(r[i] + 1), t2.resize(r[i] + 1);
        rep(j,1,r[i]) t1[j] = mul(C(r[i] + j - 1, r[i] - j), fac(j - 1));
        rep(j,0,r[i]) t2[r[i] - j] = mul((j & 1) ? mod - 1 : 1, ifc(j));
        F[i] = shiftcoeff(conv(t1, t2), r[i]);
        rep(j,1,r[i]) F[i][j] = mul(F[i][j], ifc(j - 1));
        F[i][0] = 0;
    } 
    poly f = dac(1, n);
    int ans = 0;
    for (int i = 1; i <= m; ++ i)
        addi(ans, mul(f[i], fac(i - 1)));
    cout << mul(ans, m) << '\n';
}
正常做法
#include <bits/stdc++.h>
using namespace std; 
using pii = pair<int,int>; using vi = vector<int>; using vp = vector<pii>; using ll = long long; 
using ull = unsigned long long; using db = double; using ld = long double; using lll = __int128_t;
template<typename T1, typename T2> T1 max(T1 a, T2 b) { return a > b ? a : b; }
template<typename T1, typename T2> T1 min(T1 a, T2 b) { return a < b ? a : b; }
#define multi int T; cin >> T; while ( T -- )
#define timer cerr << 1. * clock() / CLOCKS_PER_SEC << '\n';
#define iot ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define file(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define rep(i,s,t) for (register int i = (s), i##_ = (t) + 1; i < i##_; ++ i)
#define pre(i,s,t) for (register int i = (s), i##_ = (t) - 1; i > i##_; -- i)
#define eb emplace_back
#define pb pop_back
const int inf = 0x3f3f3f3f;
const ll infll = 0x3f3f3f3f3f3f3f3fll;
namespace __POLY__{
    const int N = 3e6 + 10, mod = 998244353, gen = 3;
    namespace tdef{typedef int i32;typedef unsigned int u32;typedef long long i64;typedef unsigned long long u64;typedef vector<i32>vi32;typedef vector<u32>vu32;typedef vector<i64>vi64;typedef vector<u64>vu64;}namespace math{using namespace tdef;template<typename T=int>inline T qp(i64 x,int y,i64 ans=1){for(y<0?y+=mod-1:0;y;y>>=1,x=x*x%mod)y&1?ans=ans*x%mod:0;return ans;}inline constexpr int lg(u32 x){return x==0?-1:((int)sizeof(int)*__CHAR_BIT__-1-__builtin_clz(x));}inline u32 fst_mul(u32 x,u64 p,u64 q){return x*p-(q*x>>32)*mod;}const u32 modm2=mod+mod;namespace basic_math{vu32 __fac({1,1}),__ifc({1,1}),__inv({0,1});inline void __prep(int n){static int i=2;if(i<n)for(__fac.resize(n),__ifc.resize(n),__inv.resize(n);i<n;i++)__fac[i]=1ll*i*__fac[i-1]%mod,__inv[i]=1ll*(mod-mod/i)*__inv[mod%i]%mod,__ifc[i]=1ll*__inv[i]*__ifc[i-1]%mod;}inline u32 gfac(u32 x){return __prep(x+1),__fac[x];}inline u32 gifc(u32 x){return __prep(x+1),__ifc[x];}inline u32 ginv(u32 x){return __prep(x+1),__inv[x];}inline u32 gC(u32 n,u32 m){if(n<m)return 0;return 1ll*gfac(n)*gifc(m)%mod*gifc(n-m)%mod;}}namespace cipolla{u32 I=0;struct cpl{u32 x,y;cpl(u32 _x=0,u32 _y=0):x(_x),y(_y){}inline cpl operator*(const cpl&a)const{return cpl((1ull*x*a.x+1ull*I*y%mod*a.y)%mod,(1ull*x*a.y+1ull*y*a.x)%mod);}};inline cpl cplpow(cpl a,int y,cpl b=cpl(1,0)){for(;y;y>>=1,a=a*a)if(y&1)b=b*a;return b;}inline u32 isqrt(u32 x){static mt19937 rnd(998244353);if(mod==2||!x||x==1)return x;u32 a=0;do{a=rnd()%mod;}while(qp((1ull*a*a+mod-x)%mod,mod>>1)!=mod-1);I=(1ll*a*a+mod-x)%mod;a=cplpow(cpl(a,1),(mod+1)>>1).x;return min(a,mod-a);}}using basic_math::gfac;using basic_math::gifc;using basic_math::ginv;using cipolla::isqrt;}namespace polynomial{using namespace tdef;const int maxbit=23;using math::gfac;using math::gifc;using math::ginv;using math::lg;using math::qp;namespace fast_number_theory_transform{using math::fst_mul;using math::modm2;template<class T>inline void butterfly(T*p,int bit){for(u32 i=0,j=0;i<(1u<<bit);i++){if(i>j)swap(p[i],p[j]);for(u32 l=1u<<(bit-1);(j^=l)<l;l>>=1);}}u32*_p0[maxbit+1],*_p1[maxbit+1];inline void prep(int bit){static int k=0;u64 g;for(u32*p,*q,nl;k<bit;k++){nl=1<<k;g=qp(3,mod>>(k+1));p=_p0[k]=new u32[nl<<1];q=p+nl;for(int i=p[0]=1;i<nl;i++)p[i]=p[i-1]*g%mod;for(int i=0;i<nl;i++)q[i]=(u64(p[i])<<32)/mod;g=qp(g,-1);p=_p1[k]=new u32[nl<<1];q=p+nl;for(int i=p[0]=1;i<nl;i++)p[i]=p[i-1]*g%mod;for(int i=0;i<nl;i++)q[i]=(u64(p[i])<<32)/mod;}}template<class T>inline bool chkzero(const T*p,int bit){int i=0;for(;i+16<(1<<bit);i+=16){if(p[i]|p[i^1]|p[i^2]|p[i^3]|p[i^4]|p[i^5]|p[i^6]|p[i^7]|p[i^8]|p[i^9]|p[i^10]|p[i^11]|p[i^12]|p[i^13]|p[i^14]|p[i^15])return 0;}for(;i<(1<<bit);i++)if(p[i])return 0;return 1;}void ntt(u32*a,int bit,bool f=0){prep(bit);if(chkzero(a,bit))return;for(int k=bit;k-->0;){u32*_p=_p0[k],*_q=_p+(1<<k),*_a0=a,*_a1=a+(1<<k),x,y;for(int i=0;i<1<<(bit-k-1);i++,_a0+=2<<k,_a1+=2<<k)for(int j=0;j<(1<<k);++j){x=_a0[j],y=_a1[j];_a0[j]=x+y-(x+y>=modm2)*modm2,_a1[j]=fst_mul(x+modm2-y,_p[j],_q[j]);}}for(int i=0;i<(1<<bit);i++)a[i]-=(a[i]>=modm2)*modm2,a[i]-=(a[i]>=mod)*mod;if(f)butterfly(a,bit);}void intt(u32*a,int bit,bool f=0){prep(bit);if(chkzero(a,bit))return;if(f)butterfly(a,bit);for(int k=0;k<bit;k++){u32*_p=_p1[k],*_q=_p+(1<<k),*_a0=a,*_a1=a+(1<<k),x,y;for(int i=0;i<1<<(bit-k-1);i++,_a0+=2<<k,_a1+=2<<k)for(int j=0;j<(1<<k);++j){x=_a0[j]-(_a0[j]>=modm2)*modm2,y=fst_mul(_a1[j],_p[j],_q[j]);_a0[j]=x+y,_a1[j]=x+modm2-y;}}u64 iv=mod;iv<<=bit;iv=(iv-mod+1)>>bit;for(int i=0;i<(1<<bit);i++)a[i]=a[i]*iv%mod;}}using fast_number_theory_transform::intt;using fast_number_theory_transform::ntt;
    struct poly{vu32 f;template<typename _Tp=size_t,typename _Tv=u32>poly(_Tp len=0,_Tv same_val=0):f(len,same_val){}poly(const vu32&_f):f(_f){}poly(const vi32&_f){f.resize(_f.size());for(int i=0;i<_f.size();i++){f[i]=_f[i]+((_f[i]>>31)&mod);}}template<typename T>poly(initializer_list<T>_f):poly(vector<T>(_f)){}template<typename T>poly(T*__first,T*__last):poly(vector<typename iterator_traits<T>::value_type>(__first,__last)){}inline operator vu32()const{return f;}inline vu32::iterator begin(){return f.begin();}inline vu32::iterator end(){return f.end();}void swap(poly&_f){f.swap(_f.f);}inline int degree()const{return f.size()-1;}inline int size()const{return f.size();}inline poly split(int x){f.resize(x);return*this;}inline poly&resize(int x){f.resize(x);return*this;}inline poly&redegree(int x){return f.resize(x+1),*this;}inline void clear(){f.resize(1);f[0]=0;}inline void shrink(){int ndeg=f.size()-1;while(ndeg>0&&f[ndeg]==0)ndeg--;f.resize(ndeg+1);}inline void rev(){reverse(f.begin(),f.end());}inline poly slice(int n)const{return n<=0?poly(1,1):(n<f.size()?poly(f.begin(),f.begin()+n+1):poly(*this).redegree(n));}inline u32&operator[](u32 x){return f[x];}inline u32 operator[](u32 x)const{return f[x];}inline u32 get(u32 x)const{return x<f.size()?f[x]:0;}friend istream&operator>>(istream&in,poly&x){for(int i=0;i<x.f.size();i++)in>>x.f[i];return in;}friend ostream&operator<<(ostream&out,const poly&x){out<<x.f[0];for(int i=1;i<x.f.size();i++)out<<' '<<x.f[i];return out;}inline u32*data(){return f.data();}inline const u32*data()const{return f.data();}inline poly&operator+=(const poly&a){f.resize(max(f.size(),a.f.size()));for(int i=0;i<a.f.size();i++)f[i]=f[i]+a.f[i]-(f[i]+a.f[i]>=mod)*mod;return*this;}inline poly&operator-=(const poly&a){f.resize(max(f.size(),a.f.size()));for(int i=0;i<a.f.size();i++)f[i]=f[i]-a.f[i]+(f[i]<a.f[i])*mod;return*this;}inline poly operator+(const poly&a)const{return(poly(*this)+=a);}inline poly operator-(const poly&a)const{return(poly(*this)-=a);}friend inline poly operator+(u32 a,const poly&b){return(poly(1,a)+=b);}friend inline poly operator-(u32 a,const poly&b){return(poly(1,a)-=b);}inline poly operator-()const{poly _f;_f.f.resize(f.size());for(int i=0;i<_f.f.size();i++)_f.f[i]=(f[i]!=0)*mod-f[i];return _f;}inline poly&pluswith(const poly&a){for(int i=0,i_up=min(f.size(),a.f.size());i<i_up;i++)f[i]=f[i]+a.f[i]-(f[i]+a.f[i]>=mod)*mod;return*this;}inline poly plus(const poly&a)const{return(poly(*this).pluswith(a));}inline poly&minuswith(const poly&a){for(int i=0,i_up=min(f.size(),a.f.size());i<i_up;i++)f[i]=f[i]-a.f[i]+(f[i]<a.f[i])*mod;return*this;}inline poly minus(const poly&a)const{return(poly(*this).minuswith(a));}inline poly&cornerwith(const poly&a){memcpy(f.data(),a.f.data(),min(a.f.size(),f.size())*4);return*this;}inline poly corner(const poly&a)const{return poly(*this).cornerwith(a);}inline poly&operator*=(const poly&a){int n=degree(),m=a.degree();if(n<16||m<16){f.resize(n+m+1);for(int i=n+m;i>=0;i--){f[i]=1ll*f[i]*a.f[0]%mod;for(int j=max(1,i-n),j_up=min(m,i);j<=j_up;j++)f[i]=(f[i]+1ll*f[i-j]*a.f[j])%mod;}return*this;}vu32 _f(a.f);int bit=lg(n+m)+1;f.resize(1<<bit);_f.resize(1<<bit);ntt(f.data(),bit);ntt(_f.data(),bit);for(int i=0;i<(1<<bit);i++)f[i]=1ll*f[i]*_f[i]%mod;intt(f.data(),bit);f.resize(n+m+1);return*this;}inline poly operator*(const poly&a)const{return(poly(*this)*=a);}inline poly&multiplywith(const poly&_a){poly a(_a);a.shrink();int n=degree(),m=a.degree();if(n<16||m<16){for(int i=n;i>=0;i--){f[i]=1ll*f[i]*a.f[0]%mod;for(int j=max(1,i-n),j_up=min(m,i);j<=j_up;j++)f[i]=(f[i]+1ll*f[i-j]*a.f[j])%mod;}return*this;}int bit=lg(n+m)+1;f.resize(1<<bit);a.f.resize(1<<bit);ntt(f.data(),bit);ntt(a.f.data(),bit);for(int i=0;i<(1<<bit);i++)f[i]=1ll*f[i]*a.f[i]%mod;intt(f.data(),bit);f.resize(n+1);return*this;}inline poly multiply(const poly&a)const{return(poly(*this).multiplywith(a));}template<typename T>inline friend poly operator*(const poly&a,const T&b){poly ret(a);for(int i=0;i<ret.f.size();++i)ret[i]=1ll*ret[i]*b%mod;return ret;}template<typename T>inline friend poly operator*(const T&b,const poly&a){poly ret(a);for(int i=0;i<ret.f.size();++i)ret[i]=1ll*ret[i]*b%mod;return ret;}template<typename T>inline poly&operator*=(const T&b){for(int i=0;i<f.size();++i)f[i]=1ll*f[i]*b%mod;return*this;}inline poly&operator>>=(int x){return f.resize(f.size()+x),memmove(f.data()+x,f.data(),4*(f.size()-x)),memset(f.data(),0,4*x),*this;}inline poly operator>>(int x)const{return(poly(*this)>>=x);}inline poly&operator<<=(int x){return x>=f.size()?(clear(),*this):(memmove(f.data(),f.data()+x,4*(f.size()-x)),f.resize(f.size()-x),*this);}inline poly operator<<(int x)const{return(poly(*this)<<=x);}inline poly&shiftindexwith(int x){return x>=f.size()?(memset(f.data(),0,4*f.size()),*this):(memmove(f.data(),f.data()+x,4*(f.size()-x)),memset(f.data(),0,4*x),*this);}inline poly shiftindex(int x)const{return(poly(*this).shiftindexwith(x));}inline poly inv()const;inline poly quo(const poly&g)const;inline poly&quowith(const poly&g){return f.size()==1?(f[0]=qp(g[0],-1,f[0]),*this):(*this=quo(g));}inline poly deri()const{int n=degree();poly res;res.redegree(n-1);for(int i=1;i<=n;i++)res[i-1]=1ll*f[i]*i%mod;return res;}inline poly intg(u32 C=0)const{int n=degree();poly res(1,C);res.redegree(n+1);for(int i=0;i<=n;i++)res[i+1]=1ll*ginv(i+1)*f[i]%mod;return res;}inline poly ln()const;inline poly exp()const;inline poly eval(int n,poly a)const;inline poly intp(int n,const poly&x,const poly&y);inline poly pow(u32 x,u32 modphix=-1){if(modphix==-1)modphix=x;int n=size()-1;i64 empt=0;while(empt<=n and!f[empt])++empt;if(1ll*empt*x>n)return poly(size());poly res(size());for(int i=0;i<=n-empt;++i)res[i]=f[i+empt];int val_0=res[0],inv_0=qp(val_0,mod-2),pow_0=qp(val_0,modphix);for(int i=0;i<=n-empt;++i)res[i]=1ll*res[i]*inv_0%mod;res=(res.ln()*x).exp();empt*=x;for(int i=n;i>=empt;--i)res[i]=1ll*res[i-empt]*pow_0%mod;for(int i=empt-1;i>=0;--i)res[i]=0;return res;}inline poly ivsqrt()const{int nsize=f.size(),mxb=lg(f.size()-1)+1;vu32 a(1<<mxb),_f(f);_f.resize(1<<mxb);a[0]=qp(math::isqrt(f[0]),mod-2);for(int nb=0;nb<mxb;nb++){vu32 _a(a.begin(),a.begin()+(1<<nb)),_b(_f.begin(),_f.begin()+(2<<nb));_a.resize(4<<nb);_b.resize(4<<nb);ntt(_a.data(),nb+2);ntt(_b.data(),nb+2);for(int i=0;i<(4<<nb);i++)_a[i]=1ull*(mod-_a[i])*_a[i]%mod*_a[i]%mod*_b[i]%mod,_a[i]=(_a[i]+(_a[i]&1)*mod)>>1;intt(_a.data(),nb+2);memcpy(a.data()+(1<<nb),_a.data()+(1<<nb),4<<nb);}return a.resize(nsize),a;}inline poly sqrt()const{if(f.size()==1)return poly(1,math::isqrt(f[0]));if(f.size()==2&&f[0]==1)return poly(vector<int>{1,(int)(1ll*f[1]*(mod+1)/2%mod)});int nsize=f.size(),mxb=lg(nsize-1)+1;vu32 a(1<<mxb),_f(f),_b;_f.resize(1<<mxb);a[0]=qp(math::isqrt(f[0]),mod-2);for(int nb=0;nb<mxb-1;nb++){vu32 _a(a.begin(),a.begin()+(1<<nb));_b=vu32(_f.begin(),_f.begin()+(2<<nb));_a.resize(4<<nb);_b.resize(4<<nb);ntt(_a.data(),nb+2);ntt(_b.data(),nb+2);for(int i=0;i<(4<<nb);i++)_a[i]=1ull*(mod-_a[i])*_a[i]%mod*_a[i]%mod*_b[i]%mod,_a[i]=(_a[i]+(_a[i]&1)*mod)>>1;intt(_a.data(),nb+2);memcpy(a.data()+(1<<nb),_a.data()+(1<<nb),4<<nb);}ntt(a.data(),mxb);vu32 _a(a);for(int i=0;i<(1<<mxb);i++)a[i]=1ll*a[i]*_b[i]%mod;intt(a.data(),mxb),memset(a.data()+(1<<(mxb-1)),0,2<<mxb);vu32 g0(a);ntt(a.data(),mxb),ntt(_f.data(),mxb);for(int i=0;i<(1<<mxb);i++)a[i]=(1ll*a[i]*a[i]+mod-_f[i])%mod*(mod-_a[i])%mod,a[i]=(a[i]+(a[i]&1)*mod)>>1;intt(a.data(),mxb);memcpy(g0.data()+(1<<(mxb-1)),a.data()+(1<<(mxb-1)),2<<mxb);return g0;}inline poly czt(int c,int m)const{poly ret(f);int inv=qp(c,mod-2),n=ret.size();ret.resize(m);poly F(n),G(n+m);for(int i=0,p1=1,p2=1;i<n;++i){F[n-i-1]=1ll*ret[i]*p1%mod;i&&(p2=1ll*p2*inv%mod,p1=1ll*p1*p2%mod,true);}for(int i=0,p1=1,p2=1;i<n+m;++i){G[i]=p1;i&&(p2=1ll*p2*c%mod,p1=1ll*p1*p2%mod,true);}F=F*G;for(int i=0,p1=1,p2=1;i<m;++i){ret[i]=1ll*F[i+n-1]*p1%mod;i&&(p2=1ll*p2*inv%mod,p1=1ll*p1*p2%mod,true);}return ret;}inline poly ChirpZ(int c,int m)const{return czt(c,m);}inline poly shift(int c)const{poly A(size()),B(size()),ret(size());for(int i=0;i<size();++i)A[size()-i-1]=1ll*f[i]*gfac(i)%mod;for(int i=0,pc=1;i<size();++i,pc=1ll*pc*c%mod)B[i]=1ll*pc*gifc(i)%mod;A*=B;for(int i=0;i<size();++i)ret[i]=1ll*A[size()-i-1]*gifc(i)%mod;return ret;}inline poly fdt()const{poly F(*this),E(size());for(int i=0;i<size();++i)E[i]=gifc(i);F*=E;F.resize(size());for(int i=0;i<size();++i)F[i]=1ll*F[i]*gfac(i)%mod;return F;}inline poly ifdt()const{poly F(*this),E(size());for(int i=0;i<size();++i)F[i]=1ll*F[i]*gifc(i)%mod;for(int i=0;i<size();++i)if(i&1)E[i]=mod-gifc(i);else E[i]=gifc(i);return(F*E).slice(degree());}inline poly sin()const{int omega_4=qp(gen,(mod-1)>>2);poly F=((*this)*omega_4).exp();return qp(omega_4*2,mod-2)*(F-F.inv());}inline poly cos()const{int omega_4=qp(gen,(mod-1)>>2);poly F=((*this)*omega_4).exp();return qp(2,mod-2)*(F+F.inv());}inline poly tan()const{return sin()*cos().inv();}inline poly asin()const{poly A=deri(),B=(*this)*(*this);B.resize(size());B=(1-B).ivsqrt();return(A*B).intg().slice(degree());}inline poly acos()const{poly A=(mod-1)*deri(),B=(*this)*(*this);B.resize(size());B=(1-B).ivsqrt();return(A*B).intg().slice(degree());}inline poly atan()const{poly A=deri(),B=1+(*this)*(*this);B.resize(size());B=B.inv();return(A*B).intg().slice(degree());}};
    namespace __semiconvol__{const int logbr=4,br=1<<logbr,maxdep=(maxbit-1)/logbr+1,__bf=7,bf=max(__bf,logbr-1),pbf=1<<bf;}inline poly poly::ln()const{using namespace __semiconvol__;int nsize=f.size(),mxb=lg(nsize-1)+1;math::basic_math::__prep(mxb);vu32 res(1<<mxb),__prentt[maxdep][br],_f(f);for(int i=0,k=mxb;k>bf;k-=logbr,i++){for(int j=0;j<br-1;j++){if((j<<(k-logbr))>=nsize)break;__prentt[i][j].resize(2<<(k-logbr));int nl=(j<<(k-logbr)),nr=min(((j+2)<<(k-logbr)),nsize)-nl;memcpy(__prentt[i][j].data(),_f.data()+nl,nr*4);ntt(__prentt[i][j].data(),k-logbr+1);}}function<void(int,int,int)>__div=[&res,&__prentt,&_f,&mxb,&__div](int x,int l,int r){if(r-l<=pbf){for(int i=l;i<r;i++){if(i==0)res[i]=0;else{res[i]=(1ll*i*_f[i]+mod-res[i])%mod;if(i+1<r){u64 __tmp=res[i];for(int j=i+1;j<r;j++)res[j]=(res[j]+__tmp*_f[j-i])%mod;}}}return;}int nbit=mxb-logbr*(x+1),nbr=0;vu32 __tmp[br];while(l+(nbr<<nbit)<r){__tmp[nbr].resize(2<<nbit);nbr++;}for(int i=0;i<nbr;i++){if(i!=0){intt(__tmp[i].data(),nbit+1);for(int j=0;j<(1<<nbit);j++){u32&x=res[l+(i<<nbit)+j],&y=__tmp[i][j+(1<<nbit)];x=x+y-(x+y>=mod)*mod,y=0;}}__div(x+1,l+(i<<nbit),min(l+((i+1)<<nbit),r));if(i!=nbr-1){memcpy(__tmp[i].data(),res.data()+l+(i<<nbit),4<<nbit);ntt(__tmp[i].data(),nbit+1);for(int j=i+1;j<nbr;j++)for(int k=0;k<(2<<nbit);k++)__tmp[j][k]=(__tmp[j][k]+1ll*__tmp[i][k]*__prentt[x][j-i-1][k])%mod;}}};__div(0,0,nsize);res.resize(nsize);for(int i=nsize-1;i;i--)res[i]=1ll*math::ginv(i)*res[i]%mod;return res;}inline poly poly::exp()const{using namespace __semiconvol__;int nsize=f.size(),mxb=lg(nsize-1)+1;math::basic_math::__prep(mxb);vu32 res(1<<mxb),__prentt[maxdep][br],_f(f);for(int i=0;i<nsize;i++)_f[i]=1ll*i*_f[i]%mod;for(int i=0,k=mxb;k>bf;k-=logbr,i++){for(int j=0;j<br-1;j++){if((j<<(k-logbr))>=nsize)break;__prentt[i][j].resize(2<<(k-logbr));int nl=(j<<(k-logbr)),nr=min(((j+2)<<(k-logbr)),nsize)-nl;memcpy(__prentt[i][j].data(),_f.data()+nl,nr*4);ntt(__prentt[i][j].data(),k-logbr+1);}}function<void(int,int,int)>__div=[&res,&__prentt,&_f,&mxb,&__div](int x,int l,int r){if(r-l<=pbf){for(int i=l;i<r;i++){res[i]=i==0?1:1ll*math::ginv(i)*res[i]%mod;if(i+1<r){u64 __tmp=res[i];for(int j=i+1;j<r;j++)res[j]=(res[j]+__tmp*_f[j-i])%mod;}}return;}int nbit=mxb-logbr*(x+1),nbr=0;vu32 __tmp[br];while(l+(nbr<<nbit)<r){__tmp[nbr].resize(2<<nbit);nbr++;}for(int i=0;i<nbr;i++){if(i!=0){intt(__tmp[i].data(),nbit+1);for(int j=0;j<(1<<nbit);j++){u32&x=res[l+(i<<nbit)+j],&y=__tmp[i][j+(1<<nbit)];x=x+y-(x+y>=mod)*mod,y=0;}}__div(x+1,l+(i<<nbit),min(l+((i+1)<<nbit),r));if(i!=nbr-1){memcpy(__tmp[i].data(),res.data()+l+(i<<nbit),4<<nbit);ntt(__tmp[i].data(),nbit+1);for(int j=i+1;j<nbr;j++)for(int k=0;k<(2<<nbit);k++)__tmp[j][k]=(__tmp[j][k]+1ll*__tmp[i][k]*__prentt[x][j-i-1][k])%mod;}}};__div(0,0,nsize);return res.resize(nsize),res;}inline poly poly::inv()const{using namespace __semiconvol__;int nsize=f.size(),mxb=lg(nsize-1)+1;vu32 res(1<<mxb),__prentt[maxdep][br],_f(f);u32 ivf0=qp(f[0],-1);_f[0]=0;for(int i=0,k=mxb;k>bf;k-=logbr,i++){for(int j=0;j<br-1;j++){if((j<<(k-logbr))>=nsize)break;__prentt[i][j].resize(2<<(k-logbr));int nl=(j<<(k-logbr)),nr=min(((j+2)<<(k-logbr)),nsize)-nl;memcpy(__prentt[i][j].data(),_f.data()+nl,nr*4);ntt(__prentt[i][j].data(),k-logbr+1);}}function<void(int,int,int)>__div=[&res,&__prentt,&_f,&mxb,&__div,&ivf0](int x,int l,int r){if(r-l<=pbf){for(int i=l;i<r;i++){res[i]=i==0?ivf0:1ll*ivf0*(mod-res[i])%mod;if(i+1<r){u64 __tmp=res[i];for(int j=i+1;j<r;j++)res[j]=(res[j]+__tmp*_f[j-i])%mod;}}return;}int nbit=mxb-logbr*(x+1),nbr=0;vu32 __tmp[br];while(l+(nbr<<nbit)<r){__tmp[nbr].resize(2<<nbit);nbr++;}for(int i=0;i<nbr;i++){if(i!=0){intt(__tmp[i].data(),nbit+1);for(int j=0;j<(1<<nbit);j++){u32&x=res[l+(i<<nbit)+j],&y=__tmp[i][j+(1<<nbit)];x=x+y-(x+y>=mod)*mod,y=0;}}__div(x+1,l+(i<<nbit),min(l+((i+1)<<nbit),r));if(i!=nbr-1){memcpy(__tmp[i].data(),res.data()+l+(i<<nbit),4<<nbit);ntt(__tmp[i].data(),nbit+1);for(int j=i+1;j<nbr;j++)for(int k=0;k<(2<<nbit);k++)__tmp[j][k]=(__tmp[j][k]+1ll*__tmp[i][k]*__prentt[x][j-i-1][k])%mod;}}};__div(0,0,nsize);return res.resize(nsize),res;}inline poly poly::quo(const poly&g)const{using namespace __semiconvol__;int nsize=f.size(),mxb=lg(nsize-1)+1;vu32 res(1<<mxb),__prentt[maxdep][br],_f(g.f);u32 ivf0=qp(_f[0],-1);_f[0]=0;_f.resize(nsize);for(int i=0,k=mxb;k>bf;k-=logbr,i++){for(int j=0;j<br-1;j++){if((j<<(k-logbr))>=nsize)break;__prentt[i][j].resize(2<<(k-logbr));int nl=(j<<(k-logbr)),nr=min(((j+2)<<(k-logbr)),nsize)-nl;memcpy(__prentt[i][j].data(),_f.data()+nl,nr*4);ntt(__prentt[i][j].data(),k-logbr+1);}}function<void(int,int,int)>__div=[=,&res,&__prentt,&_f,&mxb,&__div,&ivf0](int x,int l,int r){if(r-l<=pbf){for(int i=l;i<r;i++){res[i]=1ll*ivf0*(i==0?f[0]:f[i]+mod-res[i])%mod;if(i+1<r){u64 __tmp=res[i];for(int j=i+1;j<r;j++)res[j]=(res[j]+__tmp*_f[j-i])%mod;}}return;}int nbit=mxb-logbr*(x+1),nbr=0;vu32 __tmp[br];while(l+(nbr<<nbit)<r){__tmp[nbr].resize(2<<nbit);nbr++;}for(int i=0;i<nbr;i++){if(i!=0){intt(__tmp[i].data(),nbit+1);for(int j=0;j<(1<<nbit);j++){u32&x=res[l+(i<<nbit)+j],&y=__tmp[i][j+(1<<nbit)];x=x+y-(x+y>=mod)*mod,y=0;}}__div(x+1,l+(i<<nbit),min(l+((i+1)<<nbit),r));if(i!=nbr-1){memcpy(__tmp[i].data(),res.data()+l+(i<<nbit),4<<nbit);ntt(__tmp[i].data(),nbit+1);for(int j=i+1;j<nbr;j++)for(int k=0;k<(2<<nbit);k++)__tmp[j][k]=(__tmp[j][k]+1ll*__tmp[i][k]*__prentt[x][j-i-1][k])%mod;}}};__div(0,0,nsize);return res.resize(nsize),res;}namespace __multipoint_operation__{const int Len=5e5+10;poly __Q[Len<<2];poly _E_Mul(poly A,poly B){int n=A.size(),m=B.size();B.rev();B=A*B;for(int i=0;i<n;++i)A[i]=B[i+m-1];return A;}void _E_Init(int p,int l,int r,poly&a){if(l==r){__Q[p].resize(2);__Q[p][0]=1,__Q[p][1]=(a[l]?mod-a[l]:a[l]);return;}int mid=l+r>>1;_E_Init(p<<1,l,mid,a),_E_Init(p<<1|1,mid+1,r,a);__Q[p]=__Q[p<<1]*__Q[p<<1|1];}void _E_Calc(int p,int l,int r,const poly&F,poly&g){if(l==r)return void(g[l]=F[0]);poly __F(r-l+1);for(int i=0,ed=r-l+1;i<ed;++i)__F[i]=F[i];int mid=l+r>>1;_E_Calc(p<<1,l,mid,_E_Mul(__F,__Q[p<<1|1]),g);_E_Calc(p<<1|1,mid+1,r,_E_Mul(__F,__Q[p<<1]),g);}poly __P[Len<<2];void _I_Init(int p,int l,int r,const poly&x){if(l==r){__P[p].resize(2),__P[p][0]=(x[l]?mod-x[l]:0),__P[p][1]=1;return;}int mid=l+r>>1;_I_Init(p<<1,l,mid,x),_I_Init(p<<1|1,mid+1,r,x);__P[p]=__P[p<<1]*__P[p<<1|1];}poly _I_Calc(int p,int l,int r,const poly&t){if(l==r)return poly(1,t[l]);int mid=l+r>>1;poly L(_I_Calc(p<<1,l,mid,t)),R(_I_Calc(p<<1|1,mid+1,r,t));L=L*__P[p<<1|1],R=R*__P[p<<1];for(int i=0;i<(int)R.size();++i){L[i]=L[i]+R[i];if(L[i]>=mod)L[i]-=mod;}return L;}}inline poly poly::eval(int n,poly a)const{using namespace __multipoint_operation__;n=max(n,size());poly v(n);poly F(f);F.resize(n+1),a.resize(n);_E_Init(1,0,n-1,a);__Q[1].resize(n+1);_E_Calc(1,0,n-1,_E_Mul(F,__Q[1].inv()),v);return v;}inline poly poly::intp(int n,const poly&x,const poly&y){using namespace __multipoint_operation__;_I_Init(1,0,n-1,x);__P[1]=__P[1].deri();poly t=__P[1].eval(n,x);for(int i=0;i<n;++i)t[i]=1ll*y[i]*qp(t[i],mod-2)%mod;f=_I_Calc(1,0,n-1,t);return*this;}}using math::gfac;using math::gifc;using math::ginv;using math::qp;using math::basic_math::gC;using polynomial::poly;
} using namespace __POLY__;
int n, m, ans, r[N];
poly F[N], t1, t2;

poly toEGF(const poly& b) {
    poly ret(b);
    for (int i = 0; i < ret.size(); ++ i)
        ret[i] = 1ll * ret[i] * gifc(i) % mod;
    return ret;
}

poly dac(int l, int r) {
    if (l == r) return toEGF(F[l]);
    int mid = l + r >> 1;
    return dac(l, mid) * dac(mid + 1, r);
}

signed main() {
    iot;
	cin >> n; rep(i,1,n) cin >> r[i], m += r[i];
    rep(i,1,n) {
        t1.clear(), t2.clear();
        t1.resize(r[i] + 1), t2.resize(r[i] + 1);
        rep(j,1,r[i]) t1[j] = 1ll * gC(r[i] + j - 1, r[i] - j) * gfac(j - 1) % mod;
        if (i == 1) rep(j,1,r[i]) t1[j] = 1ll * t1[j] * qp(j, mod - 2) % mod;
        rep(j,0,r[i]) 
            if (j & 1) t2[r[i] - j] = mod - gifc(j);
            else t2[r[i] - j] = gifc(j);
        F[i] = t1 * t2 << r[i];
        rep(j,1,r[i]) F[i][j] = 1ll * F[i][j] * gifc(j - 1) % mod;
        F[i][0] = 0;
    } 
    poly f = dac(2, n);
    f = (f * toEGF(F[1] << 1) - f * toEGF(F[1] << 2));
    for (int i = 1; i < f.size(); ++ i)
        ans = (ans + 1ll * f[i] * gfac(i)) % mod;
    cout << 1ll * ans * m % mod << '\n';
}
posted @ 2023-01-25 12:16  joke3579  阅读(86)  评论(0编辑  收藏  举报