Skip to content

Commit bbe2231

Browse files
authored
Merge pull request #353 from hitonanode/kth-power-sum
自然数の $k$ 乗和
2 parents c6277e1 + 21faa6b commit bbe2231

File tree

3 files changed

+83
-0
lines changed

3 files changed

+83
-0
lines changed

utilities/kth_power_sum.hpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#pragma once
2+
#include <vector>
3+
4+
// Computes the sum of the k-th powers
5+
// Complexity:
6+
// - O(k) per query,
7+
// - O(k^2) precomputation (can be reduced to O(k log k) with FFT)
8+
template <class MODINT> struct kth_power_sum {
9+
10+
// generating function: x / (e^x - 1) + x
11+
// NOTE: use B(1) = 1/2 definition
12+
std::vector<MODINT> bernoulli;
13+
14+
kth_power_sum() = default;
15+
16+
void expand() {
17+
if (bernoulli.empty()) {
18+
bernoulli = {1};
19+
} else {
20+
const int k = bernoulli.size();
21+
MODINT x(0);
22+
for (int i = 0; i < k; ++i) { x = -x + bernoulli[i] * MODINT::binom(k + 1, i); }
23+
bernoulli.push_back(x / (k + 1));
24+
}
25+
}
26+
27+
// Calculate 1^k + 2^k + ... + n^k
28+
// Based on Faulhaber's formula:
29+
// S_k(n) = 1 / (k + 1) * sum_{j=0}^{k} B_j * C(k + 1, j) * n^(k + 1 - j)
30+
31+
template <class T> MODINT prefix_sum(int k, const T &n) {
32+
while ((int)bernoulli.size() <= k) expand();
33+
34+
MODINT ret(0), np(1);
35+
for (int j = k; j >= 0; --j) {
36+
np *= n;
37+
ret += MODINT::binom(k + 1, j) * bernoulli[j] * np;
38+
}
39+
return ret / (k + 1);
40+
}
41+
};

utilities/kth_power_sum.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
---
2+
title: Sum of $k$-th powers of first $n$ positive integers (自然数の $k$ 乗和)
3+
documentation_of: ./kth_power_sum.hpp
4+
---
5+
6+
「 $1$ 以上 $n$ 以下の自然数の $k$ 乗の総和」を Faulhaber の公式を用いて計算する.
7+
8+
内部で Bernoulli 数の先頭 $k + 1$ 項を計算する必要がある.このコードでは `prefix_sum()` メンバ関数が呼ばれた時点で動的に不足している部分を計算し, $\Theta(k^2)$ で動く.より高速にする必要があれば,母関数 $x / (\exp(x) - 1) + x$ (第 1 項の定義に $+1/2$ を採用している点に注意)の冪級数展開を FFT 等で計算してメンバ変数 `bernoulli` に事前に設定しておけばよい.
9+
10+
## 使用方法
11+
12+
```cpp
13+
using mint = ModInt<998244353>;
14+
kth_power_sum<mint> kp;
15+
16+
int k = 1;
17+
long long n = 10;
18+
19+
auto sum = kp.prefix_sum(k, n); // 1^k + ... + n^k
20+
21+
assert(sum == mint(55));
22+
```
23+
24+
## 問題例
25+
26+
- [No.665 Bernoulli Bernoulli - yukicoder](https://yukicoder.me/problems/no/665)
27+
- [Educational Codeforces Round 7 F. The Sum of the k-th Powers - Codeforces](https://codeforces.com/contest/622/problem/F)
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#define PROBLEM "https://yukicoder.me/problems/no/665"
2+
#include "../kth_power_sum.hpp"
3+
#include "../../modint.hpp"
4+
#include <iostream>
5+
using namespace std;
6+
7+
int main() {
8+
long long n;
9+
int k;
10+
cin >> n >> k;
11+
12+
kth_power_sum<ModInt<1000000007>> kps;
13+
14+
cout << kps.prefix_sum(k, n) << '\n';
15+
}

0 commit comments

Comments
 (0)