「模板」多项式全家桶
#include <bits/stdc++.h>
#define ll long long
#define db double
#define gc getchar
#define pc putchar
#define swap(a, b) a ^= b ^= a ^= b
using namespace std;
const int N = 1e5 + 5;
const int p = 998244353;
namespace IO
{
template <typename T>
void read(T &x)
{
x = 0; bool f = 0; char c = gc();
while(!isdigit(c)) f |= c == '-', c = gc();
while(isdigit(c)) x = (ll)x * 10 % p + c - '0', c = gc();
if(f) x = -x;
}
template <typename T>
void write(T x)
{
if(x < 0) pc('-'), x = -x;
if(x > 9) write(x / 10);
pc('0' + x % 10);
}
}
using namespace IO;
ll add(ll x) {return x < p ? x : x - p;}
ll sub(ll x) {return x < 0 ? x + p : x;}
ll qpow(ll a, int b)
{
ll res = 1;
while(b)
{
if(b & 1) res = res * a % p;
a = a * a % p, b >>= 1;
}
return res;
}
namespace Poly
{
const int G = 3;
const int Gi = 332748118;
const int inv2 = 499122177;
void Clear(ll *a, int l, int r) {for(int i = l; i < r; i++) a[i] = 0;}
void Copy(ll *a, ll *b, int len) {for(int i = 0; i < len; i++) b[i] = a[i];}
void print(ll *a, int len) {for(int i = 0; i < len; i++) write(a[i]), pc(' '); pc('\n');}
int rev[N << 2];
void calcrev(int lim)
{
for(int i = 0; i < lim; i++)
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) * (lim >> 1));
}
int calclim(int len)
{
int lim = 1;
while(lim < len) lim <<= 1;
return lim;
}
//快速数论变换
void NTT(ll *a, int lim, int type)
{
for(int i = 0; i < lim; i++)
if(i < rev[i]) swap(a[i], a[rev[i]]);
for(int mid = 1; mid < lim; mid <<= 1)
{
ll wn = qpow(type == 1 ? G : Gi, (p - 1) / (mid << 1));
for(int i = 0; i < lim; i += (mid << 1))
{
ll w = 1;
for(int j = 0; j < mid; j++, w = w * wn % p)
{
ll x = a[i + j], y = w * a[i + mid + j] % p;
a[i + j] = add(x + y);
a[i + mid + j] = sub(x - y);
}
}
}
ll limi = qpow(lim, p - 2);
if(type == -1)
for(int i = 0; i < lim; i++)
a[i] = a[i] * limi % p;
return;
}
//多项式乘法
ll A[N << 2], B[N << 2];
void Mul(ll *a, ll *b, int n, int m)
{
int lim = calclim(n + m);
Clear(A, 0, lim), Clear(B, 0, lim);
Copy(a, A, n), Copy(b, B, m);
calcrev(lim);
NTT(A, lim, 1), NTT(B, lim, 1);
for(int i = 0; i < lim; i++) A[i] = A[i] * B[i] % p;
NTT(A, lim, -1);
Copy(A, a, lim);
return;
}
//多项式求逆
ll c[N << 2];
void Inv(ll *a, ll *b, int n)
{
if(n == 1) return b[0] = qpow(a[0], p - 2), void();
Inv(a, b, (n + 1) >> 1);
int lim = calclim(n << 1);
Copy(a, c, n), Clear(c, n, lim);
calcrev(lim);
NTT(b, lim, 1), NTT(c, lim, 1);
for(int i = 0; i < lim; i++)
b[i] = sub(2ll - b[i] * c[i] % p) * b[i] % p;
NTT(b, lim, -1);
Clear(b, n, lim);
return;
}
//多项式开根
ll bi[N << 2];
void Sqrt(ll *a, ll *b, int n)
{
if(n == 1) return b[0] = 1, void();
Sqrt(a, b, (n + 1) >> 1);
Clear(bi, 0, calclim(n << 1));
Inv(b, bi, n);
Mul(bi, a, n, n);
for(int i = 0; i < n; i++) b[i] = add(bi[i] + b[i]) * inv2 % p;
Clear(b, n, calclim(n << 1));
}
//多项式除法
ll br[N << 2], bri[N << 2];
void Div(ll *a, ll *b, ll *x, ll *y, int n, int m)
{
int lim = calclim(n << 1);
Copy(b, br, m), Clear(br, m, lim), reverse(br, br + m);
Clear(bri, 0, lim), Inv(br, bri, n - m + 2);
Copy(a, x, n), Clear(x, n, lim), reverse(x, x + n);
Mul(x, bri, n, n - m + 2), Clear(x, n - m + 1, n + n - m + 2), reverse(x, x + n - m + 1);
reverse(br, br + m);
Mul(br, x, m, n - m + 2);
for(int i = 0; i < m - 1; i++) y[i] = sub(a[i] - br[i]);
return;
}
//求导
void Dif(ll *a, ll *b, int n)
{
for(int i = 1; i < n; i++)
b[i - 1] = i * a[i] % p;
b[n - 1] = 0;
}
//积分
void Int(ll *a, ll *b, int n)
{
for(int i = 1; i < n; i++)
b[i] = a[i - 1] * qpow(i, p - 2) % p;
b[0] = 0;
}
//多项式ln
ll x[N << 2], y[N << 2];
void Ln(ll *a, ll *b, int n)
{
int lim = calclim(n << 1);
Clear(x, 0, lim), Clear(y, 0, lim);
Dif(a, x, n);
Inv(a, y, n);
Mul(x, y, n, n);
Int(x, b, n);
return;
}
//多项式exp
ll lnb[N << 2];
void Exp(ll *a, ll *b, int n)
{
if(n == 1) return b[0] = 1, void();
Exp(a, b, (n + 1) >> 1);
int lim = calclim(n << 1);
Ln(b, lnb, n);
for(int i = 0; i < n; i++)
lnb[i] = sub(a[i] - lnb[i]);
lnb[0]++;
Mul(b, lnb, n, n), Clear(b, n, lim);
return;
}
//多项式快速幂
ll lna[N << 2];
void Qpow(ll *a, int k, ll *b, int n)
{
Ln(a, lna, n);
for(int i = 0; i < n; i++) lna[i] = lna[i] * k % p;
Exp(lna, b, n);
return;
}
}
using namespace Poly;
int main()
{
}
// A.S.
未完待续。。。
$$A\ drop\ of\ tear\ blurs\ memories\ of\ the\ past.$$