多项式板子

注意事项

  1. 在使用一个函数前,请确保 [lim, lim*2) 内的所有项都为 0。
  2. 请保证数组空间为 2 倍。
  3. 请确保在之前已经使用 init,参数是 lim*2。
const int MOD = 998244353, MAXN = 131072 + 5;
ll q_pow(ll a, ll b, ll p = MOD) {
	ll ret = 1;
	for (; b; a = a * a % p, b >>= 1) if (b & 1) ret = ret * a % p;
	return ret;
}
ll inv(ll x, ll p = MOD) { return q_pow(x, p - 2, p); }
inline int add(int x, int y) { return x + y < MOD ? x + y : x + y - MOD; }
inline int dec(int x, int y) { return x < y ? x - y + MOD : x - y; }
inline void ADD(int& x, int y) { x += y; if (x >= MOD) x -= MOD; }
inline void DEC(int& x, int y) { x -= y; if (x < 0) x += MOD; }

namespace poly {
	const int M = MAXN * 2;
	int rev[M], fac[M], ifac[M], I[M], Wn[M*2], iWn[M*2];
	void init(int LIM) {
		fac[0] = fac[1] = ifac[0] = ifac[1] = I[1] = 1;
		for (int i = 2; i <= LIM; ++i) {
			fac[i] = 1ll * fac[i - 1] * i %MOD;
			I[i] = 1ll * (MOD - MOD / i) * I[MOD % i] % MOD;
			ifac[i] = 1ll * ifac[i - 1] * I[i] % MOD;
		}
		for (int l = 2; l <= LIM; l <<= 1) {
			int g = q_pow(3, (MOD - 1) / l), ig = inv(g), wn = 1, iwn = 1;
			for (int j = 0; j < (l >> 1); ++j, wn=1ll*wn*g%MOD, iwn=1ll*iwn*ig%MOD) {
				Wn[l | j] = wn, iWn[l | j] = iwn;
				//if((l|j)>=390000)printf("(%d,%d)%d=%d\n",l,j,l|j,l|j);
			}
		}
	}
	void Copy(int* A, const int* B, int LIM) {
		for (int i = 0; i < LIM; ++i) A[i] = B[i];
	}
	void NTT(int* F, int LIM, int op) {
		for (int i = 0; i < LIM; ++i) if (i < rev[i]) swap(F[i], F[rev[i]]);
		for (int l = 2; l <= LIM; l <<= 1) for (int i = 0; i < LIM; i += l) {
			for (int j = 0; j < (l >> 1); ++j) {
				int x = F[i | j];
				int y = 1ll * F[i | j | (l >> 1)] * (op == -1 ? iWn[l | j] : Wn[l | j]) % MOD;
				F[i | j] = add(x, y), F[i | j | (l >> 1)] = dec(x, y);
			}
		}
		if (op == -1) {
			int invLIM = inv(LIM);
			for (int i = 0; i < LIM; ++i) F[i] = 1ll * F[i] * invLIM % MOD;
		}
	}
	int Tmul[M];
	void Multiply(int* A, const int* B, int LIM, int L) {
		for (int i = 0; i < LIM; ++i) Tmul[i] = B[i];
		for (int i = LIM; i < (LIM << 1); ++i) Tmul[i] = 0;
		for (int i = 0; i < (LIM << 1); ++i) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << L);
		NTT(A, LIM << 1, 1), NTT(Tmul, LIM << 1, 1);
		for (int i = 0; i < (LIM << 1); ++i) A[i] = 1ll * A[i] * Tmul[i] % MOD;
		NTT(A, LIM << 1, -1);
		for (int i = LIM; i < (LIM << 1); ++i) A[i] = 0;
	}
	int Tinv[M];
	void Inv(int* G, const int* F, int LIM, int L) {
		for (int i = 0; i < LIM; ++i) G[i] = 0;
		G[0] = inv(F[0]);
		for (int l = 1, lim = 2; l <= L; ++l, lim <<= 1) {
			for (int i = 0; i < lim; ++i) Tinv[i] = F[i];
			for (int i = lim; i < (lim << 1); ++i) Tinv[i] = 0;
			for (int i = 0; i < (lim << 1); ++i) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << l);
			NTT(G, lim << 1, 1), NTT(Tinv, lim << 1, 1);
			for (int i = 0; i < (lim << 1); ++i) {
				G[i] = dec(add(G[i], G[i]), 1ll * Tinv[i] * G[i] % MOD * G[i] % MOD);
			}
			NTT(G, lim << 1, -1);
			for (int i = lim; i < (lim << 1); ++i) G[i] = 0;
		}
		for (int i = 0; i < (LIM << 1); ++i) Tinv[i] = 0;
	}
	void DAO(int* F, int LIM) {
		for (int i = 0; i < LIM - 1; ++i) F[i] = 1ll * F[i + 1] * (i + 1) % MOD;
		F[LIM - 1] = 0;
	}
	void JI(int* F, int LIM) {
		for (int i = LIM - 1; i >= 1; --i) F[i] = 1ll * F[i - 1] * I[i] % MOD;
		F[0] = 0;
	}
	int Tln[M];
	void Ln(int* G, const int* F, int LIM, int L) {
		//assert(F[0] == 1)
		Copy(G, F, LIM), Inv(Tln, G, LIM, L), DAO(G, LIM);
		Multiply(G, Tln, LIM, L);
		JI(G, LIM);
		for (int i = 0; i < (LIM << 1); ++i) Tln[i] = 0;
		for (int i = LIM; i < (LIM << 1); ++i) G[i] = 0;
	}
	int Texp[M];
	void Exp(int* G, const int* F, int LIM, int L) {
		//assert(F[0] == 0);
		for (int i = 0; i < (LIM << 1); ++i) G[i] = 0;
		G[0] = 1;
		for (int l = 1, lim = 2; l <= L; ++l, lim <<= 1) {
			Ln(Texp, G, lim, l);
			for (int i = 0; i < lim; ++i) Texp[i] = dec(F[i], Texp[i]);
			ADD(Texp[0], 1);
			Multiply(G, Texp, lim, l);
			for (int i = lim; i < (lim << 1); ++i) G[i] = 0;
		}
		for (int i = LIM; i < (LIM << 1); ++i) G[i] = 0;
		for (int i = 0; i < (LIM << 1); ++i) Texp[i] = 0;
	}
};
using namespace poly;

你可能感兴趣的:(多项式板子)