232's competitive-programming templates.
polynomial
232-aka-pretty-pi
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;
}