8.14.10 ACM-ICPC 组合数学 伯努利数
组合数学中的伯努利数
在组合数学中,伯努利数(Bernoulli Numbers)是一类重要的数列,它们在数论、微积分和其他数学分支中有广泛的应用。特别是在 ACM-ICPC 编程竞赛中,伯努利数常用于求解一些复杂的数学问题。本节将介绍伯努利数的定义、性质以及在编程竞赛中的应用。
一、伯努利数的定义
伯努利数 BnB_nBn 是通过下面的递推公式定义的:
其中 (n+1k)\binom{n+1}{k}(kn+1) 是二项式系数。
二、伯努利数的性质
- 奇次伯努利数:除了 B1B_1B1 之外,所有奇次伯努利数都是零,即 B
- 生成函数:伯努利数的生成函数为:
- 递推关系:根据递推公式,可以逐项计算伯努利数。例如:
三、伯努利数在编程竞赛中的应用
在 ACM-ICPC 编程竞赛中,伯努利数可以用于解决多种复杂的数学问题。以下是一些典型应用:
1. 高次求和
伯努利数常用于高次求和公式。例如,求 ∑k=1nkm\sum_{k=1}^{n} k^m∑k=1nkm 可以通过伯努利多项式来简化。公式为:
2. 欧拉-麦克劳林公式
伯努利数在欧拉-麦克劳林求和公式中也有重要应用,用于将离散求和转换为积分形式,简化计算:
3. 组合计数问题
在组合数学中,伯努利数用于解决一些计数问题,如计算 Stirling 数和 Bell 数。
四、编程实现
以下是伯努利数的简单递归计算方法:
#include <iostream>
#include <vector>
using namespace std;
const int MAXN = 100;
vector<double> bernoulli(MAXN + 1);
void compute_bernoulli() {
bernoulli[0] = 1.0;
for (int m = 1; m <= MAXN; ++m) {
bernoulli[m] = 0.0;
for (int k = 0; k < m; ++k) {
bernoulli[m] += (bernoulli[k] / (m - k + 1)) * (m + 1);
}
bernoulli[m] = 1.0 - bernoulli[m];
}
}
int main() {
compute_bernoulli();
for (int i = 0; i <= 10; ++i) {
cout << "B_" << i << " = " << bernoulli[i] << endl;
}
return 0;
}
总结
伯努利数在组合数学中具有重要地位,其广泛应用于数论、高次求和、欧拉-麦克劳林公式以及组合计数问题中。掌握伯努利数的性质和计算方法,对于解决 ACM-ICPC 编程竞赛中的复杂数学问题具有重要意义。通过以上内容的学习和代码实现,读者可以更好地理解和应用伯努利数。
二、等幂求和
伯努利数是由雅各布·伯努利在研究 mmm 次幂和的公式时发现的。我们记:
伯努利观察了如下一列公式,勾画出一种模式:
三、递推公式
伯努利数的递推公式如下:
伯努利数由隐含的递推关系定义:
四、伯努利数的性质
- 奇次伯努利数:除了 B1B_1B1 之外,所有奇次伯努利数都是零,即 B2k+1=0B_{2k+1} = 0B2k+1=0(对于 k≥1k \geq 1k≥1)。
- 生成函数:伯努利数的生成函数为: xex−1=∑n=0∞Bnxnn!\frac{x}{e^x - 1} = \sum_{n=0}^{\infty} B_n \frac{x^n}{n!}ex−1x=∑n=0∞Bnn!xn
- 递推关系:根据递推公式,可以逐项计算伯努利数。例如: B2=16,B4=−130,B6=142,等等B_2 = \frac{1}{6}, \quad B_4 = -\frac{1}{30}, \quad B_6 = \frac{1}{42}, \quad \text{等等}B2=61,B4=−301,B6=421,等等
五、证明伯努利数的递推关系
利用归纳法可以证明伯努利数的递推关系。这个证明方法来自《Concrete Mathematics》。
通过二项式系数的恒等变换和归纳法,可以得到以下公式:
将原式中两边都减去 Sm+1(n)S_{m+1}(n)Sm+1(n) 后可以得到:
不妨设 Δ=Sm(n)−S^m(n)\Delta = S_m(n) - \hat{S}_m(n)Δ=Sm(n)−S^m(n),并且将 S^j(n)\hat{S}_j(n)S^j(n) 展开,那么有:
将第二个求和顺序改为逆向,再将组合数的写法恒等变换可以得到:
对两个求和符号进行交换,可以得到:
对 (m+1j)(jk)\binom{m+1}{j}\binom{j}{k}(jm+1)(kj) 进行恒等变换:
那么式子就变成了:
考虑我们前面提到过的递归关系:
代入后可以得到:
于是 Δ=0\Delta = 0Δ=0,且有 Sm(n)=S^m(n)S_m(n) = \hat{S}_m(n)Sm(n)=S^m(n)。
六、利用指数生成函数证明
对递推式:
两边都加上 Bm+1B_{m+1}Bm+1,即得到:
设 B(z)=∑i≥0Bii!ziB(z) = \sum_{i \ge 0}\frac{B_i}{i!}z^iB(z)=∑i≥0i!Bizi,注意到左边为卷积形式,故:
调换求和顺序:
代入 B(z)=zez−1B(z) = \frac{z}{e^z - 1}B(z)=ez−1z:
故得证。
七、参考实现
以下是伯努利数的参考实现代码:
typedef long long ll;
const int maxn = 10000;
const int mod = 1e9 + 7;
ll B[maxn]; // 伯努利数
ll C[maxn][maxn]; // 组合数
ll inv[maxn]; // 逆元(计算伯努利数)
void init() {
// 预处理组合数
for (int i = 0; i < maxn; i++) {
C[i][0] = C[i][i] = 1;
for (int k = 1; k < i; k++) {
C[i][k] = (C[i - 1][k] % mod + C[i - 1][k - 1] % mod) % mod;
}
}
// 预处理逆元
inv[1] = 1;
for (int i = 2; i < maxn; i++) {
inv[i] = (mod - mod / i) * inv[mod % i] % mod;
}
// 预处理伯努利数
B[0] = 1;
for (int i = 1; i < maxn; i++) {
ll ans = 0;
if (i == maxn - 1) break;
for (int k = 0; k < i; k++) {
ans += C[i + 1][k] * B[k];
ans %= mod;
}
ans = (ans * (-inv[i + 1]) % mod + mod) % mod;
B[i] = ans;
}
}
总结
伯努利数在组合数学中占有重要地位,其应用范围包括高次求和、欧拉-麦克劳林公式、组合计数等。掌握伯努利数的定义、性质和计算方法,对于解决 ACM-ICPC 编程竞赛中的复杂数学问题具有重要意义。通过本文的学习和代码实现,读者可以更好地理解和应用伯努利数。