提交记录 17046


用户 题目 状态 得分 用时 内存 语言 代码长度
whx1003 1002i. 【模板题】多项式乘法 Accepted 100 20.939 ms 11828 KB C++11 18.42 KB
提交时间 评测时间
2021-11-30 18:10:08 2021-11-30 18:10:12
#include <ctime>
#include <cstdio>

#define nya(neko...) fprintf(stderr, neko)

__attribute__((destructor))
inline void ptime() {
	nya("\nTime: %.3lf(s)\n", 1. * clock() / CLOCKS_PER_SEC);
}

#include <cmath>
#include <random>
#include <vector>
#include <algorithm>

using ll = long long;
using vec = std::vector<ll>;
constexpr ll mod = 998244353, gen = 3;
constexpr ll inv2 = (mod + 1) / 2;
constexpr int maxn = 2E+5 + 5;

namespace IObuf {
	using IObuf_t = int;

	constexpr int LEN = 1 << 20;
	
	char ibuf[LEN + 5], *p1 = ibuf, *p2 = ibuf;
	char obuf[LEN + 5], *p3 = obuf;
	
	inline char get() {
#ifdef WHX1003
		return getchar();
#else
		return p1 == p2 && (p2 = (p1 = ibuf) + fread(ibuf, 1, LEN, stdin), p1 == p2) ? EOF : *p1++;
#endif
	}
	
	inline IObuf_t getint(char c = get(), IObuf_t x = 0, IObuf_t op = 1) {
		while(c < '0' || c > '9') c == '-' && (op = -op), c = get();
		while(c >= '0' && c <= '9') x = x * 10 + c - 48, c = get();
		return x * op;
	}
	
	__attribute__((destructor))
	inline char* flush() { fwrite(obuf, 1, p3 - obuf, stdout); return p3 = obuf; }
	inline void put(char c) {
#ifdef WHX1003
		putchar(c);
#else
		p3 == obuf + LEN && flush(); *p3++ = c; return;
#endif
	}
	
	inline void putint(IObuf_t x, char suf = '\n') {
		static char sta[30];
		static int top = 0;
		
		if(x < 0) put('-'), x = -x;
		if(!x) put('0');
		else {
			while(x) sta[++top] = x % 10 + 48, x /= 10;
			while(top) put(sta[top--]);
		} put(suf);
	}

	inline void putstr(const char *s, char suf = '\n') {
		while(*s != '\0') put(*s++);
		put(suf);
	}
} // IObuf
using IObuf::getint;
using IObuf::putint;
using IObuf::putstr;

inline ll fsp(ll a, ll b, ll res = 1) {
	for(a %= mod; b; a = a * a % mod, b >>= 1)
		b & 1 ? res = res * a % mod : 0; return res;
}

namespace Math {
	int L = -1;
	
	ll _Fac[maxn << 2], _Inv[maxn << 2], _inv[maxn << 2];
	inline void pre(int l) {
		if(L == -1) {
			_Fac[0] = _Fac[1] = 1;
			_Inv[0] = _Inv[1] = 1;
			_inv[1] = 1, L = 1;
			if(l <= L) return;
		}
		
		for(int i = L + 1; i <= l; ++i) {
			_inv[i] = _inv[mod % i] * (mod - mod / i) % mod;
			_Fac[i] = _Fac[i - 1] * i % mod;
			_Inv[i] = _Inv[i - 1] * _inv[i] % mod;
		}
		
		L = l;
	}
	
	inline ll Fac(int n) { if(L < n) pre(n); return _Fac[n]; }
	inline ll Inv(int n) { if(L < n) pre(n); return _Inv[n]; }
	inline ll inv(int n) { if(L < n) pre(n); return _inv[n]; }
	inline ll binom(int n, int k) {
		if(k < 0 || n < k) return 0;
		return Fac(n) * Inv(k) % mod * Inv(n - k) % mod;
	}
} // Math

namespace Cipolla {
	ll imgn;
	struct complex {
		ll re, im;
		inline complex(ll _r = 0, ll _i = 0) : re(_r), im(_i) {}
		inline complex operator*(const complex &d) const {
			return complex((re * d.re + im * d.im % mod * imgn) % mod, (re * d.im + im * d.re) % mod);
		}
	};
	
	inline complex mod_fsp(complex a, ll b, complex res = 1) {
		for(b %= mod - 1; b; a = a * a, b >>= 1)
			if(b & 1) res = res * a; return res;
	}
	
	inline ll solve(ll x) {
		std::mt19937 rnd(time(0));
		if(mod == 2 || !x) return x;
		
		ll a = 0;
		while(true) {
			a = rnd() % mod;
			if(fsp(mod + a * a - x, mod - 1 >> 1) == mod - 1) break;
		} imgn = (a * a - x + mod) % mod;
		
		ll ans = mod_fsp(complex(a, 1), mod + 1 >> 1).re;
		return std::min(ans, mod - ans);
	}
} // Cipolla

namespace Poly {
	inline constexpr ll Add(ll x, ll y) { return x + y >= mod ? x + y - mod : x + y; }
	inline constexpr ll Sub(ll x, ll y) { return x < y ? x - y + mod : x - y; }
		
	struct poly {
		vec f;
		
		// init
		
		inline poly(ll v = 0) : f(1) { f[0] = v; }
		inline poly(const vec &_f) : f(_f) {}
		inline poly(std::initializer_list<ll> init) : f(init) {}
		
		// tools
		
		inline ll operator[](int p) const { return f[p]; }
		inline ll &operator[](int p) { return f[p]; }
		
		inline int deg() const { return f.size() - 1; }
		inline void redeg(int d) { f.resize(d + 1); }
		
		inline poly slice(int d) const {
			if(d < f.size())
				return vec(f.begin(), f.begin() + d + 1);
			
			vec res(f);
			return res.resize(d + 1), res;
		}
	
		inline void print(int d) const {
			for(int i = 0; i <= d && i < f.size(); ++i) putint(f[i], ' ');
			for(int i = f.size(); i <= d; ++i) putint(0, ' ');
			IObuf::put('\n');
		}
		
		inline ll calc(ll x) const {
			ll res = 0, tmp = 1;
			for(int i = 0; i <= deg(); ++i) {
				res = (res + f[i] * tmp) % mod;
				tmp = tmp * x % mod;
			} return res;
		}
		
		// operators
		
		inline poly operator+(const poly &P) const {
			vec res(std::max(deg(), P.deg()) + 1);
			
			for(int i = std::min(deg(), P.deg()); i >= 0; --i) res[i] = Add(f[i], P[i]);
			for(int i = std::min(deg(), P.deg()) + 1; i < res.size(); ++i) res[i] = i <= deg() ? f[i] : P[i];
			return res;
		}
		
		inline poly operator-() const {
			poly res(f);
			for(int i = 0; i < f.size(); ++i)
				res[i] ? res[i] = mod - res[i] : 0;
			return res;
		}
		
		inline poly operator-(const poly &P) const { return operator+(-P); }
		
		inline poly operator<<(int d) const {
			poly res; res.redeg(d + deg());
			for(int i = 0; i <= deg(); ++i)
				res[i + d] = f[i];
			return res;
		}
		
		inline poly operator>>(int d) const {
			if(d > deg()) return poly(0);
			return vec(f.begin() + d, f.end());
		}
		
		inline poly operator*(ll v) const {
			v = (v % mod + mod) % mod;
			
			poly res(f);
			for(int i = 0; i <= deg(); ++i)
				res[i] = res[i] * v % mod;
			return res;
		}
		
		inline poly operator*(const poly &P) const;				// redeg to max(deg(), P.deg())
		inline poly operator/(const poly &P) const;
		inline poly operator%(const poly &P) const;
		
		inline poly mul(const poly &P) const;					// redeg to deg() + P.deg()
		
		inline poly intg(ll C) const;
		inline poly der() const;
		
		inline poly inv() const;
		inline poly quo(const poly &P) const;
		
		inline void divln(poly &res, int bit, int l, int r) const;
		inline poly ln() const;
		
		inline void divexp(poly &res, int bit, int l, int r) const;
		inline poly exp() const;
		
		inline poly pow(ll k) const;
		
		inline poly sqrt() const;
		inline poly invsqrt() const;
	};
	
	namespace NTT_namespace {
		#define ctz(x) __builtin_ctz(x)
		
		constexpr int rank2 = ctz(mod - 1);

		ll root[rank2 + 1];   // root[i]^(2^i) == 1
		ll iroot[rank2 + 1];  // root[i] * iroot[i] == 1
		ll rate2[rank2], irate2[rank2];
		ll rate3[rank2], irate3[rank2];

		__attribute__((constructor))
		inline void NTTpre() {
			root[rank2] = fsp(gen, mod - 1 >> rank2);
			iroot[rank2] = fsp(root[rank2], mod - 2);
			for(int i = rank2 - 1; i >= 0; --i) {
				root[i] = root[i + 1] * root[i + 1] % mod;
				iroot[i] = iroot[i + 1] * iroot[i + 1] % mod;
			}

			{
				ll prod = 1, iprod = 1;
				for (int i = 0; i <= rank2 - 2; i++) {
					rate2[i] = root[i + 2] * prod % mod;
					irate2[i] = iroot[i + 2] * iprod % mod;
					prod = prod * iroot[i + 2] % mod;
					iprod = iprod * root[i + 2] % mod;
				}
			}

			{
				ll prod = 1, iprod = 1;
				for(int i = 0; i <= rank2 - 3; i++) {
					rate3[i] = root[i + 3] * prod % mod;
					irate3[i] = iroot[i + 3] * iprod % mod;
					prod = prod * iroot[i + 3] % mod;
					iprod = iprod * root[i + 3] % mod;
				}
			}
		}
		
		inline void butterfly(poly &a, int h) {
			if(a.deg() < (1 << h) - 1) a.redeg((1 << h) - 1);

			int len = 0;  // a[i, i+(n>>len), i+2*(n>>len), ..] is transformed
			while(len < h) {
				if(h - len == 1) {
					int p = 1 << (h - len - 1);
					
					ll rot = 1;
					for(int s = 0; s < (1 << len); ++s) {
						int offset = s << (h - len);
						for(int i = 0; i < p; ++i) {
							ll l = a[i + offset];
							ll r = a[i + offset + p] * rot % mod;
							a[i + offset] = Add(l, r);
							a[i + offset + p] = Sub(l, r);
						}
						if(s + 1 != (1 << len))
							rot = rot * rate2[ctz(~(unsigned int)(s))] % mod;
					}
					++len;
				} else {
					// 4-base
					int p = 1 << (h - len - 2);
					ll rot = 1, imag = root[2];
					for(int s = 0; s < (1 << len); ++s) {
						ll rot2 = rot * rot % mod;
						ll rot3 = rot2 * rot % mod;
						int offset = s << (h - len);
						for(int i = 0; i < p; ++i) {
							ll mod2 = mod * mod;
							ll a0 = a[i + offset + 0 * p];
							ll a1 = a[i + offset + 1 * p] * rot;
							ll a2 = a[i + offset + 2 * p] * rot2;
							ll a3 = a[i + offset + 3 * p] * rot3;
							ll a1na3imag = (a1 + mod2 - a3) % mod * imag;
							ll na2 = mod2 - a2;

							a[i + offset] = (a0 + a2 + a1 + a3) % mod;
							a[i + offset + 1 * p] = (a0 + a2 + (2 * mod2 - (a1 + a3))) % mod;
							a[i + offset + 2 * p] = (a0 + na2 + a1na3imag) % mod;
							a[i + offset + 3 * p] = (a0 + na2 + (mod2 - a1na3imag)) % mod;
						}
						if(s + 1 != (1 << len))
							rot = rot * rate3[ctz(~(unsigned int)(s))] % mod;
					}
					len += 2;
				}
			}
		}
		
		inline void invbutterfly(poly &a, int h) {
			if(a.deg() < (1 << h) - 1) a.redeg((1 << h) - 1);

			int len = h;  // a[i, i+(n>>len), i+2*(n>>len), ..] is transformed
			while(len) {
				if(len == 1) {
					int p = 1 << (h - len);
					
					ll irot = 1;
					for(int s = 0; s < (1 << (len - 1)); ++s) {
						int offset = s << (h - len + 1);
						for(int i = 0; i < p; ++i) {
							ll l = a[i + offset];
							ll r = a[i + offset + p];
							a[i + offset] = Add(l, r);
							a[i + offset + p] = Sub(l, r) * irot % mod;
						}
						if (s + 1 != (1 << (len - 1)))
							irot = irot * irate2[ctz(~(unsigned int)(s))] % mod;
					}
					--len;
				} else {
					// 4-base
					int p = 1 << (h - len);
					ll irot = 1, iimag = iroot[2];
					for(int s = 0; s < (1 << (len - 2)); ++s) {
						ll irot2 = irot * irot % mod;
						ll irot3 = irot2 * irot % mod;
						int offset = s << (h - len + 2);
						for(int i = 0; i < p; ++i) {
							ll a0 = a[i + offset + 0 * p];
							ll a1 = a[i + offset + 1 * p];
							ll a2 = a[i + offset + 2 * p];
							ll a3 = a[i + offset + 3 * p];
							ll a2na3iimag = Sub(a2, a3) * iimag % mod;
		
							a[i + offset] = (a0 + a1 + a2 + a3) % mod;
							a[i + offset + 1 * p] = (a0 + (mod - a1) + a2na3iimag) * irot % mod;
							a[i + offset + 2 * p] = (a0 + a1 + (mod - a2) + (mod - a3)) * irot2 % mod;
							a[i + offset + 3 * p] = (a0 + (mod - a1) + (mod - a2na3iimag)) * irot3 % mod;
						}
						if(s + 1 != (1 << (len - 2)))
							irot = irot * irate3[ctz(~(unsigned int)(s))] % mod;
					}
					len -= 2;
				}
			}
			
			int N = 1 << h;
			
			ll invN = fsp(N, mod - 2);
			for(int i = 0; i < N; ++i) a[i] = a[i] * invN % mod;
		}
		
		inline void NTT(poly &f, int bit, int op) {
			if(op == 1) butterfly(f, bit);
			else invbutterfly(f, bit);
		}

		#undef ctz
	} // NTT_namespace
	using NTT_namespace::NTT;
	
	bool __WayToDeg = 0;
	inline poly poly::operator*(const poly &P) const {
		if(std::max(deg(), P.deg()) <= 128) {
			poly res; res.redeg(deg() + P.deg());
			for(int i = 0; i <= deg(); ++i)
				for(int j = 0; j <= P.deg(); ++j)
					(res[i + j] += f[i] * P[j]) %= mod;
			
			if(!__WayToDeg) res.redeg(std::max(deg(), P.deg()));
			return res;
		}
		
		poly F(f), G = P;
		
		int bit = 0, N = 1;
        while(N <= F.deg() + G.deg()) ++bit, N <<= 1;
		
		NTT(F, bit, 1), NTT(G, bit, 1);
		for(int i = 0; i < N; ++i)
			F[i] = F[i] * G[i] % mod;
		NTT(F, bit, -1);
		
		if(!__WayToDeg) return F.slice(std::max(deg(), P.deg()));
		else return F.slice(deg() + P.deg());
	}
	
	inline poly poly::operator/(const poly &P) const {
		if(deg() < P.deg()) return 0;
		
		poly g = vec(f.rbegin(), f.rend()), h = vec(P.f.rbegin(), P.f.rend());
		poly res = g.slice(deg() - P.deg()).quo(h.slice(deg() - P.deg()));
		res.redeg(deg() - P.deg()), reverse(res.f.begin(), res.f.end());
		
		return res;
	}
	
	inline poly poly::operator%(const poly &P) const {
		return operator-(operator/(P) * P).slice(P.deg() - 1);
	}

	inline poly poly::mul(const poly &P) const {
		__WayToDeg = 1; poly H = operator*(P);
		return __WayToDeg = 0, H;
	}
	
	inline poly poly::inv() const {
		poly g = fsp(f[0], mod - 2);
		for(int stp = 1; (1 << stp - 1) <= deg(); ++stp) {
			int N = 1 << stp;
			
			poly h = slice(N - 1), g0 = g;
			
			NTT(g, stp, 1), NTT(h, stp, 1);
			for(int i = 0; i < N; ++i)
				h[i] = h[i] * g[i] % mod;
			NTT(h, stp, -1);
			
			for(int i = 0; i < (N >> 1); ++i) h[i] = 0;
			
			NTT(h, stp, 1);
			for(int i = 0; i < N; ++i)
				g[i] = g[i] * h[i] % mod;
			NTT(g, stp, -1);
			
			for(int i = 0; i < (N >> 1); ++i) g[i] = 0;
			g = g0 - g;
		} return g.slice(deg());
	}
	
	inline poly poly::der() const {
		poly res; res.redeg(deg() - 1);
		for(int i = 1; i <= deg(); ++i)
			res[i - 1] = f[i] * i % mod;
		return res;
	}
	
	inline poly poly::intg(ll C = 0) const {
		poly res = C; res.redeg(deg() + 1);
		for(int i = 0; i <= deg(); ++i)
			res[i + 1] = f[i] * Math::inv(i + 1) % mod;
		return res;
	}
	
	inline poly poly::quo(const poly &P) const {
		if(deg() == 0) return fsp(P[0], mod - 2, f[0]);
		
		int bit = 0, N = 1;
		while(N <= P.deg()) ++bit, N <<= 1;
		
		poly g0 = P.slice((N >> 1) - 1).inv(), q0;
		poly h0 = slice((N >> 1) - 1);
		
		NTT(g0, bit, 1), NTT(h0, bit, 1), q0.redeg(N - 1);
		for(int i = 0; i < N; ++i)
			q0[i] = g0[i] * h0[i] % mod;
		NTT(q0, bit, -1), q0.redeg((N >> 1) - 1);
		
		poly q = q0, f0 = P;
		
		NTT(f0, bit, 1), NTT(q0, bit, 1);
		for(int i = 0; i < N; ++i)
			f0[i] = f0[i] * q0[i] % mod;
		NTT(f0, bit, -1), f0 = f0 - f;
		for(int i = 0; i < (N >> 1); ++i) f0[i] = 0;
		
		NTT(f0, bit, 1);
		for(int i = 0; i < N; ++i)
			f0[i] = f0[i] * g0[i] % mod;
		NTT(f0, bit, -1);
		
		for(int i = 0; i < (N >> 1); ++i) f0[i] = 0;
		return (q - f0).slice(deg());
	}
	
	const int logB = 4, B = 1 << logB;
	
	poly __divln_G[32][B];
	inline void poly::divln(poly &res, int bit, int l, int r) const {
		if(r - l <= 128) {
			r = std::min(r, deg() + 1);
			for(int i = l; i < r; ++i) {
				if(i == 0) res[i] = 0;
				else res[i] = (f[i] + mod - res[i] % mod * Math::inv(i) % mod) % mod;
				for(int j = i + 1; j < r; ++j)
					(res[j] += res[i] * f[j - i] % mod * i) %= mod;
			} return;
		}
		
		int dif = (r - l) / B, L = 0;
		
		poly w[B];
		while(L < B) {
			if(l + L * dif > deg()) break;
			w[L++].redeg(dif * 2 - 1);
		}
		
		for(int i = 0; i < L; ++i) {
			if(i != 0) {
				for(int j = 0; j < dif * 2; ++j) w[i][j] %= mod;
				
				Poly::NTT(w[i], bit - logB + 1, -1);
				for(int j = 0; j < dif; ++j)
					res[l + i * dif + j] += w[i][j + dif];
			}
			
			divln(res, bit - logB, l + i * dif, l + (i + 1) * dif);
			
			if(i != L - 1) {
				poly H; H.redeg(dif * 2 - 1);
				for(int j = 0; j < dif; ++j)
					H[j] = res[j + l + i * dif] * (j + l + i * dif) % mod;
				
				NTT(H, bit - logB + 1, 1);
				for(int j = i + 1; j < L; ++j)
					for(int k = 0; k < dif * 2; ++k)
						w[j][k] += H[k] * __divln_G[bit][j - i - 1][k];
			}
		}
	}
	
	inline poly poly::ln() const {
		poly res;
		
		int bit = 0, N = 1; while(N <= deg()) ++bit, N <<= 1;
		
		res.redeg(N - 1);
		for(int b = bit; b >= logB; b -= logB) {
			int dif = 1 << (b - logB);
			for(int i = 0; i < B - 1; ++i) {
				if(dif * i > deg()) break;
				__divln_G[b][i].redeg(dif * 2 - 1);
				for(int j = 0; j < dif * 2 && i * dif + j <= deg(); ++j)
					__divln_G[b][i][j] = f[j + dif * i];
				NTT(__divln_G[b][i], b - logB + 1, 1);
			}
		}
		
		return divln(res, bit, 0, N), res;
	}
	
	poly __divexp_G[32][B];
	inline void poly::divexp(poly &res, int bit, int l, int r) const {
		if(r - l <= 128) {
			r = std::min(r, deg() + 1);
			for(int i = l; i < r; ++i) {
				if(i == 0) res[i] = 1;
				else res[i] = res[i] % mod * Math::inv(i) % mod;
				for(int j = i + 1; j < r; ++j)
					(res[j] += res[i] * f[j - i] % mod * (j - i)) %= mod;
			} return;
		}
		
		int dif = (r - l) / B, L = 0;
		
		poly w[B];
		while(L < B) {
			if(l + L * dif > deg()) break;
			w[L++].redeg(dif * 2 - 1);
		}
		
		for(int i = 0; i < L; ++i) {
			if(i != 0) {
				for(int j = 0; j < dif * 2; ++j) w[i][j] %= mod;
				
				Poly::NTT(w[i], bit - logB + 1, -1);
				for(int j = 0; j < dif; ++j)
					res[l + i * dif + j] += w[i][j + dif];
			}
			
			divexp(res, bit - logB, l + i * dif, l + (i + 1) * dif);
			
			if(i != L - 1) {
				poly H; H.redeg(dif * 2 - 1);
				for(int j = 0; j < dif; ++j)
					H[j] = res[j + l + i * dif];
				
				NTT(H, bit - logB + 1, 1);
				for(int j = i + 1; j < L; ++j)
					for(int k = 0; k < dif * 2; ++k)
						w[j][k] += H[k] * __divexp_G[bit][j - i - 1][k];
			}
			
			if(L == i << 1) for(int j = i + 1; j < L; ++j)
                for(int k = 0; k < dif * 2; ++k) w[j].f[k] %= mod;
		}
	}
	
	inline poly poly::exp() const {
		poly res;
		
		int bit = 0, N = 1; while(N <= deg()) ++bit, N <<= 1;
		
		res.redeg(N - 1);
		for(int b = bit; b >= logB; b -= logB) {
			int dif = 1 << (b - logB);
			for(int i = 0; i < B - 1; ++i) {
				if(dif * i > deg()) break;
				__divexp_G[b][i].redeg(dif * 2 - 1);
				for(int j = 0; j < dif * 2 && i * dif + j <= deg(); ++j)
					__divexp_G[b][i][j] = f[j + dif * i] * (j + dif * i) % mod;
				NTT(__divexp_G[b][i], b - logB + 1, 1);
			}
		}
		
		return divexp(res, bit, 0, N), res.slice(deg());
	}
	
	inline poly poly::pow(ll k) const { return (ln() * k).exp(); }
	
	inline poly poly::sqrt() const {
		poly g = Cipolla::solve(operator[](0)), h0 = fsp(g[0], mod - 2);
		for(int stp = 1; (1 << stp - 1) <= deg(); ++stp) {
			int N = 1 << stp;
			
			poly h = h0, g0 = g;
			
			NTT(g, stp - 1, 1);
			for(int i = 0; i < (N >> 1); ++i)
				g[i] = g[i] * g[i] % mod;
			NTT(g, stp - 1, -1), g = g - slice(N - 1);
			for(int i = 0; i < (N >> 1); ++i)
				(g[i + (N >> 1)] += g[i]) %= mod, g[i] = 0;
			
			g.redeg(N - 1), h.redeg(N - 1);
			
			NTT(g, stp, 1), NTT(h, stp, 1);
			for(int i = 0; i < N; ++i)
				g[i] = g[i] * h[i] % mod;
			NTT(g, stp, -1);
			
			for(int i = 0; i < (N >> 1); ++i) g[i] = 0;
			g = g0 - g * ((mod + 1) / 2);
			
			if((1 << stp) <= deg()) {
				h = h0; poly f0 = slice(N - 1);
				
				h.redeg((N << 1) - 1), f0.redeg((N << 1) - 1);
				
				NTT(h, stp + 1, 1), NTT(f0, stp + 1, 1);
				for(int i = 0; i < (N << 1); ++i)
					h[i] = f0[i] * h[i] % mod * h[i] % mod * h[i] % mod;
				NTT(h, stp + 1, -1);
				
				h = (h - h0) * inv2;
				for(int i = 0; i < (N >> 1); ++i) h[i] = 0;
				
				h0 = h0 - h.slice(N - 1);
			}
		} return g.slice(deg());
	}

	inline poly poly::invsqrt() const {
		poly h0 = fsp(Cipolla::solve(operator[](0)), mod - 2);
		for(int stp = 1; (1 << stp - 1) <= deg(); ++stp) {
			int N = 1 << stp;

			poly h = h0, f0 = slice(N - 1);
			
			h.redeg((N << 1) - 1), f0.redeg((N << 1) - 1);
			
			NTT(h, stp + 1, 1), NTT(f0, stp + 1, 1);
			for(int i = 0; i < (N << 1); ++i)
				h[i] = f0[i] * h[i] % mod * h[i] % mod * h[i] % mod;
			NTT(h, stp + 1, -1);
			
			h = (h - h0) * inv2;
			for(int i = 0; i < (N >> 1); ++i) h[i] = 0;
			
			h0 = h0 - h.slice(N - 1);
		} return h0.slice(deg());
	}
} // Poly
using Poly::poly;

int main() {
	int n = getint(), m = getint();
	poly F, G; F.redeg(n), G.redeg(m);
	for(int i = 0; i <= n; ++i) F[i] = getint();
	for(int i = 0; i <= m; ++i) G[i] = getint();
	F.mul(G).print(n + m);
}

CompilationN/AN/ACompile OKScore: N/A

Subtask #1 Testcase #136.62 us104 KBAcceptedScore: 0

Subtask #1 Testcase #220.497 ms11 MB + 484 KBAcceptedScore: 100

Subtask #1 Testcase #38.499 ms5 MB + 912 KBAcceptedScore: 0

Subtask #1 Testcase #48.502 ms5 MB + 892 KBAcceptedScore: 0

Subtask #1 Testcase #538.03 us104 KBAcceptedScore: 0

Subtask #1 Testcase #637.28 us104 KBAcceptedScore: 0

Subtask #1 Testcase #736.6 us104 KBAcceptedScore: 0

Subtask #1 Testcase #819.421 ms10 MB + 364 KBAcceptedScore: 0

Subtask #1 Testcase #919.492 ms10 MB + 364 KBAcceptedScore: 0

Subtask #1 Testcase #1018.595 ms9 MB + 144 KBAcceptedScore: 0

Subtask #1 Testcase #1120.939 ms11 MB + 564 KBAcceptedScore: 0

Subtask #1 Testcase #1217.009 ms9 MB + 836 KBAcceptedScore: 0

Subtask #1 Testcase #1336.19 us104 KBAcceptedScore: 0


Judge Duck Online | 评测鸭在线
Server Time: 2026-03-18 05:37:50 | Loaded in 1 ms | Server Status
个人娱乐项目,仅供学习交流使用 | 捐赠