This documentation is automatically generated by online-judge-tools/verification-helper
View the Project on GitHub HyunjaeLee/Algorithms
#include "math/dirichlet_series.hpp"
#ifndef DIRICHLET_SERIES_HPP #define DIRICHLET_SERIES_HPP #include <algorithm> #include <cassert> #include <cmath> #include <numeric> #include <type_traits> #include <utility> #include <vector> template <typename T> struct dirichlet_series { dirichlet_series() : dirichlet_series(0) {} explicit dirichlet_series(long long n) : dirichlet_series(n, opt_size_dense(n)) {} template <typename F, typename Prefix> dirichlet_series(long long n, F f, Prefix prefix) : dirichlet_series(n, opt_size_dense(n), f, prefix) {} dirichlet_series(long long n, long long size_dense) : n_(n), size_dense_(size_dense), size_sparse_(n_ / (size_dense_ + 1)), data_(size_dense_ + 1), sum_dense_(size_dense_ + 1), sum_sparse_(size_sparse_ + 1) { assert(static_cast<long long>(std::sqrt(n_)) <= size_dense_); } template <typename F, typename Prefix> dirichlet_series(long long n, long long size_dense, F f, Prefix prefix) : n_(n), size_dense_(size_dense), size_sparse_(n_ / (size_dense_ + 1)), data_(size_dense_ + 1), sum_dense_(size_dense_ + 1), sum_sparse_(size_sparse_ + 1) { assert(static_cast<long long>(std::sqrt(n_)) <= size_dense_); if constexpr (std::is_invocable_r_v<T, F, long long>) { for (auto i = 1LL; i <= size_dense_; ++i) { data_[i] = f(i); } } else { f(data_); assert(static_cast<long long>(data_.size()) == size_dense_ + 1); } std::partial_sum(data_.begin(), data_.end(), sum_dense_.begin()); for (auto i = 1LL; i <= size_sparse_; ++i) { sum_sparse_[i] = prefix(internal_div(n_, i)); } }; const T &operator[](long long pos) const { assert(1 <= pos && pos <= size_dense_); return data_[pos]; } T &operator[](long long pos) { assert(1 <= pos && pos <= size_dense_); return data_[pos]; } T sum(long long pos) const { if (pos <= 0) { return T(0); } if (1 <= pos && pos <= size_dense_) { return sum_dense_[pos]; } else { const auto x = internal_div(n_, pos); assert(1 <= x && x <= size_sparse_ && internal_div(n_, (pos + 1)) + 1 == x); return sum_sparse_[x]; } } dirichlet_series &operator+=(const dirichlet_series &other) { assert_size(other); for (auto i = 1LL; i <= size_dense_; ++i) { data_[i] += other.data_[i]; sum_dense_[i] += other.sum_dense_[i]; } for (auto i = 1LL; i <= size_sparse_; ++i) { sum_sparse_[i] += other.sum_sparse_[i]; } return *this; } dirichlet_series &operator-=(const dirichlet_series &other) { assert_size(other); for (auto i = 1LL; i <= size_dense_; ++i) { data_[i] -= other.data_[i]; sum_dense_[i] -= other.sum_dense_[i]; } for (auto i = 1LL; i <= size_sparse_; ++i) { sum_sparse_[i] -= other.sum_sparse_[i]; } return *this; } dirichlet_series &operator*=(const dirichlet_series &other) { assert_size(other); dirichlet_series result(n_, size_dense_); for (auto i = 1LL; i <= size_dense_; ++i) { for (auto j = 1LL; i * j <= size_dense_; ++j) { result.data_[i * j] += data_[i] * other.data_[j]; } } std::partial_sum(std::next(result.data_.begin()), result.data_.end(), std::next(result.sum_dense_.begin())); for (auto i = 1LL; i <= size_sparse_; ++i) { const auto x = internal_div(n_, i); auto j = 1LL; for (; j * j <= x; ++j) { result.sum_sparse_[i] += data_[j] * other.sum(internal_div(x, j)) + sum(internal_div(x, j)) * other.data_[j]; } result.sum_sparse_[i] -= sum(j - 1) * other.sum(j - 1); } *this = std::move(result); return *this; } dirichlet_series &operator/=(const dirichlet_series &other) { assert_size(other); assert(other[1] != T(0)); if (this == &other) { *this = identity(n_, size_dense_); return *this; } if constexpr (std::is_integral_v<T>) { assert(std::abs(other[1]) == T(1)); } const auto inv = T(1) / other[1]; for (auto i = 1LL; i <= size_dense_; ++i) { data_[i] *= inv; for (auto j = 2LL; i * j <= size_dense_; ++j) { data_[i * j] -= data_[i] * other.data_[j]; } } partial_sum(std::next(data_.begin()), data_.end(), std::next(sum_dense_.begin())); for (auto i = size_sparse_; 1 <= i; --i) { const auto x = internal_div(n_, i); auto val = sum_sparse_[i]; sum_sparse_[i] = T(0); auto j = 1LL; for (; j * j <= x; ++j) { val -= data_[j] * other.sum(internal_div(x, j)) + sum(internal_div(x, j)) * other.data_[j]; } val += sum(j - 1) * other.sum(j - 1); val *= inv; sum_sparse_[i] = val; } return *this; } dirichlet_series &pow(long long k) { assert(k >= 0); auto result(identity(n_, size_dense_)); while (k) { if (k & 1) { result *= *this; } *this *= *this; k >>= 1; } *this = std::move(result); return *this; } friend dirichlet_series operator+(const dirichlet_series &lhs, const dirichlet_series &rhs) { auto result(lhs); result += rhs; return result; }; friend dirichlet_series operator-(const dirichlet_series &lhs, const dirichlet_series &rhs) { auto result(lhs); result -= rhs; return result; }; friend dirichlet_series operator*(const dirichlet_series &lhs, const dirichlet_series &rhs) { auto result(lhs); result *= rhs; return result; }; friend dirichlet_series operator/(const dirichlet_series &lhs, const dirichlet_series &rhs) { auto result(lhs); result /= rhs; return result; }; template <typename... Args> static dirichlet_series identity(Args &&...args) { dirichlet_series result(std::forward<Args>(args)...); result[1] = T(1); std::fill(std::next(result.sum_dense_.begin()), result.sum_dense_.end(), T(1)); std::fill(std::next(result.sum_sparse_.begin()), result.sum_sparse_.end(), T(1)); return result; } template <typename... Args> static dirichlet_series zeta(Args &&...args) { dirichlet_series result(std::forward<Args>(args)...); std::fill(std::next(result.data_.begin()), result.data_.end(), T(1)); std::iota(std::next(result.sum_dense_.begin()), result.sum_dense_.end(), T(1)); for (auto i = 1LL; i <= result.size_sparse_; ++i) { const auto x = internal_div(result.n_, i); result.sum_sparse_[i] = T(x); } return result; } template <typename... Args> static dirichlet_series zeta_shift_1(Args &&...args) { dirichlet_series result(std::forward<Args>(args)...); std::iota(std::next(result.data_.begin()), result.data_.end(), T(1)); std::partial_sum(std::next(result.data_.begin()), result.data_.end(), std::next(result.sum_dense_.begin())); for (auto i = 1LL; i <= result.size_sparse_; ++i) { const auto x = internal_div(result.n_, i); result.sum_sparse_[i] = T(x) * T(x + 1) / T(2); } return result; } template <typename... Args> static dirichlet_series zeta_shift(long long k, Args &&...args) { assert(0 <= k); if (k == 0) { return zeta(std::forward<Args>(args)...); } else if (k == 1) { return zeta_shift_1(std::forward<Args>(args)...); } dirichlet_series result(std::forward<Args>(args)...); for (auto i = 1LL; i <= result.size_dense_; ++i) { result.data_[i] = T(i).pow(k); } std::partial_sum(std::next(result.data_.begin()), result.data_.end(), std::next(result.sum_dense_.begin())); if (result.size_sparse_ == 0) { return result; } std::vector<T> y(k + 2); for (auto i = 0LL; i < k + 2; ++i) { y[i] = T(i).pow(k); } std::partial_sum(y.begin(), y.end(), y.begin()); for (auto i = 1LL; i <= result.size_sparse_; ++i) { const auto x = internal_div(result.n_, i); result.sum_sparse_[i] = interpolate(y, x); } return result; } template <typename... Args> static dirichlet_series mu(Args &&...args) { auto result(identity(std::forward<Args>(args)...)); result /= zeta(std::forward<Args>(args)...); return result; } template <typename... Args> static dirichlet_series phi(Args &&...args) { auto result(zeta_shift_1(std::forward<Args>(args)...)); result /= zeta(std::forward<Args>(args)...); return result; } private: void assert_size(const dirichlet_series &other) { assert(n_ == other.n_ && size_dense_ == other.size_dense_ && size_sparse_ == other.size_sparse_); } static long long opt_size_dense(long long n) { if (n <= 1) { return n; } else { return static_cast<long long>( std::max(std::sqrt(n), std::pow(n, 2.0 / 3) / std::log(n))); } } static long long internal_div(long long x, long long y) { return static_cast<long long>(static_cast<double>(x) / static_cast<double>(y)); } static T interpolate(const std::vector<T> &y, T x) { const auto n = static_cast<long long>(y.size()); if (const auto i = static_cast<long long>(x.val()); 0 <= i && i < n) { return y[i]; } T f(1); for (auto i = 1LL; i < n; ++i) { f *= T(i); } std::vector<T> finv(n); finv[n - 1] = f.inv(); for (auto i = n - 2; 0 <= i; --i) { finv[i] = finv[i + 1] * T(i + 1); } std::vector<T> prefix(n), suffix(n); prefix[0] = suffix[n - 1] = 1; for (auto i = 1LL; i < n; ++i) { prefix[i] = prefix[i - 1] * (i - 1 - x); } for (auto i = n - 2; i >= 0; --i) { suffix[i] = suffix[i + 1] * (i + 1 - x); } auto sum = T(0); for (auto i = 0LL; i < n; ++i) { const auto val = y[i] * prefix[i] * suffix[i] * finv[i] * finv[n - 1 - i]; sum += ((i & 1) ? -val : val); } return sum; } long long n_, size_dense_, size_sparse_; std::vector<T> data_, sum_dense_, sum_sparse_; }; #endif // DIRICHLET_SERIES_HPP
#line 1 "math/dirichlet_series.hpp" #include <algorithm> #include <cassert> #include <cmath> #include <numeric> #include <type_traits> #include <utility> #include <vector> template <typename T> struct dirichlet_series { dirichlet_series() : dirichlet_series(0) {} explicit dirichlet_series(long long n) : dirichlet_series(n, opt_size_dense(n)) {} template <typename F, typename Prefix> dirichlet_series(long long n, F f, Prefix prefix) : dirichlet_series(n, opt_size_dense(n), f, prefix) {} dirichlet_series(long long n, long long size_dense) : n_(n), size_dense_(size_dense), size_sparse_(n_ / (size_dense_ + 1)), data_(size_dense_ + 1), sum_dense_(size_dense_ + 1), sum_sparse_(size_sparse_ + 1) { assert(static_cast<long long>(std::sqrt(n_)) <= size_dense_); } template <typename F, typename Prefix> dirichlet_series(long long n, long long size_dense, F f, Prefix prefix) : n_(n), size_dense_(size_dense), size_sparse_(n_ / (size_dense_ + 1)), data_(size_dense_ + 1), sum_dense_(size_dense_ + 1), sum_sparse_(size_sparse_ + 1) { assert(static_cast<long long>(std::sqrt(n_)) <= size_dense_); if constexpr (std::is_invocable_r_v<T, F, long long>) { for (auto i = 1LL; i <= size_dense_; ++i) { data_[i] = f(i); } } else { f(data_); assert(static_cast<long long>(data_.size()) == size_dense_ + 1); } std::partial_sum(data_.begin(), data_.end(), sum_dense_.begin()); for (auto i = 1LL; i <= size_sparse_; ++i) { sum_sparse_[i] = prefix(internal_div(n_, i)); } }; const T &operator[](long long pos) const { assert(1 <= pos && pos <= size_dense_); return data_[pos]; } T &operator[](long long pos) { assert(1 <= pos && pos <= size_dense_); return data_[pos]; } T sum(long long pos) const { if (pos <= 0) { return T(0); } if (1 <= pos && pos <= size_dense_) { return sum_dense_[pos]; } else { const auto x = internal_div(n_, pos); assert(1 <= x && x <= size_sparse_ && internal_div(n_, (pos + 1)) + 1 == x); return sum_sparse_[x]; } } dirichlet_series &operator+=(const dirichlet_series &other) { assert_size(other); for (auto i = 1LL; i <= size_dense_; ++i) { data_[i] += other.data_[i]; sum_dense_[i] += other.sum_dense_[i]; } for (auto i = 1LL; i <= size_sparse_; ++i) { sum_sparse_[i] += other.sum_sparse_[i]; } return *this; } dirichlet_series &operator-=(const dirichlet_series &other) { assert_size(other); for (auto i = 1LL; i <= size_dense_; ++i) { data_[i] -= other.data_[i]; sum_dense_[i] -= other.sum_dense_[i]; } for (auto i = 1LL; i <= size_sparse_; ++i) { sum_sparse_[i] -= other.sum_sparse_[i]; } return *this; } dirichlet_series &operator*=(const dirichlet_series &other) { assert_size(other); dirichlet_series result(n_, size_dense_); for (auto i = 1LL; i <= size_dense_; ++i) { for (auto j = 1LL; i * j <= size_dense_; ++j) { result.data_[i * j] += data_[i] * other.data_[j]; } } std::partial_sum(std::next(result.data_.begin()), result.data_.end(), std::next(result.sum_dense_.begin())); for (auto i = 1LL; i <= size_sparse_; ++i) { const auto x = internal_div(n_, i); auto j = 1LL; for (; j * j <= x; ++j) { result.sum_sparse_[i] += data_[j] * other.sum(internal_div(x, j)) + sum(internal_div(x, j)) * other.data_[j]; } result.sum_sparse_[i] -= sum(j - 1) * other.sum(j - 1); } *this = std::move(result); return *this; } dirichlet_series &operator/=(const dirichlet_series &other) { assert_size(other); assert(other[1] != T(0)); if (this == &other) { *this = identity(n_, size_dense_); return *this; } if constexpr (std::is_integral_v<T>) { assert(std::abs(other[1]) == T(1)); } const auto inv = T(1) / other[1]; for (auto i = 1LL; i <= size_dense_; ++i) { data_[i] *= inv; for (auto j = 2LL; i * j <= size_dense_; ++j) { data_[i * j] -= data_[i] * other.data_[j]; } } partial_sum(std::next(data_.begin()), data_.end(), std::next(sum_dense_.begin())); for (auto i = size_sparse_; 1 <= i; --i) { const auto x = internal_div(n_, i); auto val = sum_sparse_[i]; sum_sparse_[i] = T(0); auto j = 1LL; for (; j * j <= x; ++j) { val -= data_[j] * other.sum(internal_div(x, j)) + sum(internal_div(x, j)) * other.data_[j]; } val += sum(j - 1) * other.sum(j - 1); val *= inv; sum_sparse_[i] = val; } return *this; } dirichlet_series &pow(long long k) { assert(k >= 0); auto result(identity(n_, size_dense_)); while (k) { if (k & 1) { result *= *this; } *this *= *this; k >>= 1; } *this = std::move(result); return *this; } friend dirichlet_series operator+(const dirichlet_series &lhs, const dirichlet_series &rhs) { auto result(lhs); result += rhs; return result; }; friend dirichlet_series operator-(const dirichlet_series &lhs, const dirichlet_series &rhs) { auto result(lhs); result -= rhs; return result; }; friend dirichlet_series operator*(const dirichlet_series &lhs, const dirichlet_series &rhs) { auto result(lhs); result *= rhs; return result; }; friend dirichlet_series operator/(const dirichlet_series &lhs, const dirichlet_series &rhs) { auto result(lhs); result /= rhs; return result; }; template <typename... Args> static dirichlet_series identity(Args &&...args) { dirichlet_series result(std::forward<Args>(args)...); result[1] = T(1); std::fill(std::next(result.sum_dense_.begin()), result.sum_dense_.end(), T(1)); std::fill(std::next(result.sum_sparse_.begin()), result.sum_sparse_.end(), T(1)); return result; } template <typename... Args> static dirichlet_series zeta(Args &&...args) { dirichlet_series result(std::forward<Args>(args)...); std::fill(std::next(result.data_.begin()), result.data_.end(), T(1)); std::iota(std::next(result.sum_dense_.begin()), result.sum_dense_.end(), T(1)); for (auto i = 1LL; i <= result.size_sparse_; ++i) { const auto x = internal_div(result.n_, i); result.sum_sparse_[i] = T(x); } return result; } template <typename... Args> static dirichlet_series zeta_shift_1(Args &&...args) { dirichlet_series result(std::forward<Args>(args)...); std::iota(std::next(result.data_.begin()), result.data_.end(), T(1)); std::partial_sum(std::next(result.data_.begin()), result.data_.end(), std::next(result.sum_dense_.begin())); for (auto i = 1LL; i <= result.size_sparse_; ++i) { const auto x = internal_div(result.n_, i); result.sum_sparse_[i] = T(x) * T(x + 1) / T(2); } return result; } template <typename... Args> static dirichlet_series zeta_shift(long long k, Args &&...args) { assert(0 <= k); if (k == 0) { return zeta(std::forward<Args>(args)...); } else if (k == 1) { return zeta_shift_1(std::forward<Args>(args)...); } dirichlet_series result(std::forward<Args>(args)...); for (auto i = 1LL; i <= result.size_dense_; ++i) { result.data_[i] = T(i).pow(k); } std::partial_sum(std::next(result.data_.begin()), result.data_.end(), std::next(result.sum_dense_.begin())); if (result.size_sparse_ == 0) { return result; } std::vector<T> y(k + 2); for (auto i = 0LL; i < k + 2; ++i) { y[i] = T(i).pow(k); } std::partial_sum(y.begin(), y.end(), y.begin()); for (auto i = 1LL; i <= result.size_sparse_; ++i) { const auto x = internal_div(result.n_, i); result.sum_sparse_[i] = interpolate(y, x); } return result; } template <typename... Args> static dirichlet_series mu(Args &&...args) { auto result(identity(std::forward<Args>(args)...)); result /= zeta(std::forward<Args>(args)...); return result; } template <typename... Args> static dirichlet_series phi(Args &&...args) { auto result(zeta_shift_1(std::forward<Args>(args)...)); result /= zeta(std::forward<Args>(args)...); return result; } private: void assert_size(const dirichlet_series &other) { assert(n_ == other.n_ && size_dense_ == other.size_dense_ && size_sparse_ == other.size_sparse_); } static long long opt_size_dense(long long n) { if (n <= 1) { return n; } else { return static_cast<long long>( std::max(std::sqrt(n), std::pow(n, 2.0 / 3) / std::log(n))); } } static long long internal_div(long long x, long long y) { return static_cast<long long>(static_cast<double>(x) / static_cast<double>(y)); } static T interpolate(const std::vector<T> &y, T x) { const auto n = static_cast<long long>(y.size()); if (const auto i = static_cast<long long>(x.val()); 0 <= i && i < n) { return y[i]; } T f(1); for (auto i = 1LL; i < n; ++i) { f *= T(i); } std::vector<T> finv(n); finv[n - 1] = f.inv(); for (auto i = n - 2; 0 <= i; --i) { finv[i] = finv[i + 1] * T(i + 1); } std::vector<T> prefix(n), suffix(n); prefix[0] = suffix[n - 1] = 1; for (auto i = 1LL; i < n; ++i) { prefix[i] = prefix[i - 1] * (i - 1 - x); } for (auto i = n - 2; i >= 0; --i) { suffix[i] = suffix[i + 1] * (i + 1 - x); } auto sum = T(0); for (auto i = 0LL; i < n; ++i) { const auto val = y[i] * prefix[i] * suffix[i] * finv[i] * finv[n - 1 - i]; sum += ((i & 1) ? -val : val); } return sum; } long long n_, size_dense_, size_sparse_; std::vector<T> data_, sum_dense_, sum_sparse_; };