This documentation is automatically generated by online-judge-tools/verification-helper
#include "utilities/kth_power_sum.hpp"
「 $1$ 以上 $n$ 以下の自然数の $k$ 乗の総和」を Faulhaber の公式を用いて計算する.
内部で Bernoulli 数の先頭 $k + 1$ 項を計算する必要がある.このコードでは prefix_sum()
メンバ関数が呼ばれた時点で動的に不足している部分を計算し, $\Theta(k^2)$ で動く.より高速にする必要があれば,母関数 $x / (\exp(x) - 1) + x$ (第 1 項の定義に $+1/2$ を採用している点に注意)の冪級数展開を FFT 等で計算してメンバ変数 bernoulli
に事前に設定しておけばよい.
using mint = ModInt<998244353>;
kth_power_sum<mint> kp;
int k = 1;
long long n = 10;
auto sum = kp.prefix_sum(k, n); // 1^k + ... + n^k
assert(sum == mint(55));
#pragma once
#include <vector>
// Computes the sum of the k-th powers
// Complexity:
// - O(k) per query,
// - O(k^2) precomputation (can be reduced to O(k log k) with FFT)
template <class MODINT> struct kth_power_sum {
// generating function: x / (e^x - 1) + x
// NOTE: use B(1) = 1/2 definition
std::vector<MODINT> bernoulli;
kth_power_sum() = default;
void expand() {
if (bernoulli.empty()) {
bernoulli = {1};
} else {
const int k = bernoulli.size();
MODINT x(0);
for (int i = 0; i < k; ++i) { x = -x + bernoulli[i] * MODINT::binom(k + 1, i); }
bernoulli.push_back(x / (k + 1));
}
}
// Calculate 1^k + 2^k + ... + n^k
// Based on Faulhaber's formula:
// S_k(n) = 1 / (k + 1) * sum_{j=0}^{k} B_j * C(k + 1, j) * n^(k + 1 - j)
template <class T> MODINT prefix_sum(int k, const T &n) {
while ((int)bernoulli.size() <= k) expand();
MODINT ret(0), np(1);
for (int j = k; j >= 0; --j) {
np *= n;
ret += MODINT::binom(k + 1, j) * bernoulli[j] * np;
}
return ret / (k + 1);
}
};
#line 2 "utilities/kth_power_sum.hpp"
#include <vector>
// Computes the sum of the k-th powers
// Complexity:
// - O(k) per query,
// - O(k^2) precomputation (can be reduced to O(k log k) with FFT)
template <class MODINT> struct kth_power_sum {
// generating function: x / (e^x - 1) + x
// NOTE: use B(1) = 1/2 definition
std::vector<MODINT> bernoulli;
kth_power_sum() = default;
void expand() {
if (bernoulli.empty()) {
bernoulli = {1};
} else {
const int k = bernoulli.size();
MODINT x(0);
for (int i = 0; i < k; ++i) { x = -x + bernoulli[i] * MODINT::binom(k + 1, i); }
bernoulli.push_back(x / (k + 1));
}
}
// Calculate 1^k + 2^k + ... + n^k
// Based on Faulhaber's formula:
// S_k(n) = 1 / (k + 1) * sum_{j=0}^{k} B_j * C(k + 1, j) * n^(k + 1 - j)
template <class T> MODINT prefix_sum(int k, const T &n) {
while ((int)bernoulli.size() <= k) expand();
MODINT ret(0), np(1);
for (int j = k; j >= 0; --j) {
np *= n;
ret += MODINT::binom(k + 1, j) * bernoulli[j] * np;
}
return ret / (k + 1);
}
};