template <typename Int> Int *karatsuba_polymul(Int *a, Int *b, size_t n){ if (n <= 32) { Int *r = new Int[n << 1 | 1](); for (size_t i = 0; i <= n; ++i) for (size_t j = 0; j <= n; ++j) r[i + j] += a[i] * b[j]; return r; } size_t m = (n >> 1) + 1; Int *z0, *z1, *z2; z0 = karatsuba_polymul(a, b, m - 1); z2 = karatsuba_polymul(a + m, b + m, n - m);
for (size_t i = 0; i + m <= n; ++i) a[i] += a[i + m]; for (size_t i = 0; i + m <= n; ++i) b[i] += b[i + m]; z1 = karatsuba_polymul(a, b, m - 1); for (size_t i = 0; i + m <= n; ++i) a[i] -= a[i + m]; for (size_t i = 0; i + m <= n; ++i) b[i] -= b[i + m];
for (size_t i = 0; i <= (m - 1) << 1; ++i) z1[i] -= z0[i]; for (size_t i = 0; i <= (n - m) << 1; ++i) z1[i] -= z2[i];
Int *r = new Int[m << 2 | 1](); for (size_t i = 0; i <= (m - 1) << 1; ++i) r[i] += z0[i]; for (size_t i = 0; i <= (m - 1) << 1; ++i) r[i + m] += z1[i]; for (size_t i = 0; i <= (n - m) << 1; ++i) r[i + (m << 1)] += z2[i];
template <typename T> constexprvoidchange(vector<T> &a){ size_t n = a.size(); vector<size_t> rev(n); for (size_t i = 0; i < n; ++i) { rev[i] = rev[i >> 1] >> 1; if (i & 1) rev[i] |= n >> 1; if (i < rev[i]) swap(a[i], a[rev[i]]); } }
template <int32_t on = 1> constexprvoidfft(vector<Complex> y) { static_assert(on == 1 || on == -1, "on must be 1 or -1"); change(y); for (size_t h = 2; h <= y.size(); h <<= 1) { Complex wn(cos(2 * M_PI / h), sin(on * 2 * M_PI / h)); for (size_t j = 0; j < y.size(); j += h) { Complex w(1, 0); for (size_t k = j; k < j + (h >> 1); ++k, w *= wn) { Complex u = y[k], t = w * y[k + (h >> 1)]; y[k] = u + t, y[k + (h >> 1)] = u - t; } } } ifconstexpr(on == -1) for(int i = 0; i < len; ++i) y[i] /= len; }