-
polynomial232's competitive-programming templates. 2024. 9. 21. 21:32
TODO : add ntt?
template <typename T> using Polynomial = std::vector<T>; namespace polynomial { using F = long double; using complexF = std::complex<F>; constexpr F pi = 3.1415926535897932L; void fft(std::vector<complexF>& a) { int n = int(a.size()); for (int i = 1, rev_i = 0; i < n; ++i) { for (int bit = n >> 1; ; bit >>= 1) { if (((rev_i ^= bit) & bit) != 0) { break; } } if (i < rev_i) { std::swap(a[i], a[rev_i]); } } for (int b = 1; b < n; b <<= 1) { F angle = pi / b; complexF w(std::cos(angle), std::sin(angle)); for (int s = 0; s < n; s += b << 1) { complexF theta(1, 0); // for higher precision, use theta(std::cos(angle * i), std::sin(angle * i)) (slower) for (int i = 0; i < b; ++i) { std::tie(a[s + i], a[s + i + b]) = std::pair {a[s + i] + theta * a[s + i + b], a[s + i] - theta * a[s + i + b]}; theta *= w; } } } } void ifft(std::vector<complexF>& a) { int n = int(a.size()); std::reverse(std::next(a.begin()), a.end()); fft(a); for (auto& x : a) { x /= n; } } template <typename T> Polynomial<T> multiply(const Polynomial<T>& a, const Polynomial<T>& b) { if (a.empty() || b.empty()) { return {}; } int n = 1; while (n < int(a.size()) + int(b.size()) - 1) { n <<= 1; } std::vector<complexF> ca(n); std::copy(a.begin(), a.end(), ca.begin()); std::vector<complexF> cb(n); std::copy(b.begin(), b.end(), cb.begin()); fft(ca); fft(cb); for (int i = 0; i < n; ++i) { ca[i] *= cb[i]; } ifft(ca); Polynomial<T> res(a.size() + b.size() - 1); for (int i = 0; i < int(a.size()) + int(b.size()) - 1; ++i) { res[i] = std::llround(ca[i].real()); } return res; } } // namespace polynomial template <typename T> Polynomial<T> operator+(const Polynomial<T>& a, const Polynomial<T>& b) { Polynomial<T> res(std::max(a.size(), b.size())); for (int i = 0; i < int(a.size()); ++i) { res[i] += a[i]; } for (int i = 0; i < int(b.size()); ++i) { res[i] += b[i]; } return res; } template <typename T> Polynomial<T> operator-(const Polynomial<T>& a, const Polynomial<T>& b) { Polynomial<T> res(std::max(a.size(), b.size())); for (int i = 0; i < int(a.size()); ++i) { res[i] += a[i]; } for (int i = 0; i < int(b.size()); ++i) { res[i] -= b[i]; } return res; } template <typename T> Polynomial<T>& operator+=(Polynomial<T>& a, const Polynomial<T>& b) { a.resize(std::max(a.size(), b.size())); for (int i = 0; i < int(b.size()); ++i) { a[i] += b[i]; } return a; } template <typename T> Polynomial<T>& operator-=(Polynomial<T>& a, const Polynomial<T>& b) { a.resize(std::max(a.size(), b.size())); for (int i = 0; i < int(b.size()); ++i) { a[i] -= b[i]; } return a; } template <typename T> Polynomial<T> operator*(const Polynomial<T>& a, const Polynomial<T>& b) { return polynomial::multiply(a, b); } template <typename T> Polynomial<T>& operator*=(Polynomial<T>& a, const Polynomial<T>& b) { return a = a * b; }
'232's competitive-programming templates.' 카테고리의 다른 글
MinMaxPQ (1) 2024.10.03 Centroid, CentroidTree (0) 2024.09.26 lcs_algo (0) 2024.09.17 Trie (1) 2024.09.16 OfflineDynamicConnectivity (0) 2024.09.16