8.14.5 ACM-ICPC 组合数学:斐波那契数列
一、斐波那契数列的定义与背景
斐波那契数列(Fibonacci sequence)是一个在数学和计算机科学中具有重要意义的数列。它由意大利数学家斐波那契在他的著作《Liber Abaci》中首次引入。这个数列的每一个元素都是前两个元素的和,从而形成了一个递归的结构。
斐波那契数列的定义如下:
对于 n≥2n \geq 2n≥2:
这个数列的前几项为:0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
二、斐波那契数列的性质
斐波那契数列具有许多有趣的数学性质和应用。下面列出一些常见的性质:
-
递归性质:如定义所示,斐波那契数列是一个递归数列,每一个数都是前两个数之和。
-
通项公式:斐波那契数列的通项公式为:
-
矩阵表示:斐波那契数列可以用矩阵乘法来表示:
-
黄金比例:随着 nnn 的增大,F(n+1)F(n)\frac{F(n+1)}{F(n)}F(n)F(n+1) 趋近于黄金比例 ϕ\phiϕ。
三、斐波那契数列的计算方法
1. 递归法
最直接的方法是使用递归。递归法的实现简单,但是效率低,因为存在大量重复计算。
def fibonacci_recursive(n):
if n <= 1:
return n
return fibonacci_recursive(n-1) + fibonacci_recursive(n-2)
2. 记忆化递归法
通过记忆化技术,可以避免重复计算,显著提高递归方法的效率。
def fibonacci_memoization(n, memo={}):
if n in memo:
return memo[n]
if n <= 1:
return n
memo[n] = fibonacci_memoization(n-1, memo) + fibonacci_memoization(n-2, memo)
return memo[n]
3. 动态规划法
动态规划方法通过迭代的方式计算斐波那契数列,避免了递归带来的栈溢出问题和重复计算。
def fibonacci_dynamic_programming(n):
if n <= 1:
return n
fib = [0, 1]
for i in range(2, n+1):
fib.append(fib[i-1] + fib[i-2])
return fib[n]
4. 矩阵快速幂法
矩阵快速幂法利用矩阵乘法和快速幂技术,可以在对数时间内计算斐波那契数。
def matrix_mult(A, B):
return [
[A[0][0]*B[0][0] + A[0][1]*B[1][0], A[0][0]*B[0][1] + A[0][1]*B[1][1]],
[A[1][0]*B[0][0] + A[1][1]*B[1][0], A[
[1][0]*B[0][1] + A[1][1]*B[1][1]]
]
def matrix_pow(A, n):
result = [[1, 0], [0, 1]]
base = A
while n > 0:
if n % 2 == 1:
result = matrix_mult(result, base)
base = matrix_mult(base, base)
n //= 2
return result
def fibonacci_matrix(n):
if n <= 1:
return n
F = [[1, 1], [1, 0]]
result = matrix_pow(F, n-1)
return result[0][0]
四、斐波那契数列的应用 斐波那契数列在许多领域有广泛的应用,包括但不限于:
1. **算法设计**:斐波那契堆、斐波那契查找等数据结构和算法中。
2. **数论**:斐波那契数具有许多有趣的数论性质,如斐波那契质数、斐波那契数列的模运算等。
3. **计算几何**:斐波那契数列与黄金比例相关,在图形和自然界中广泛存在。
4. **动态规划问题**:许多动态规划问题可以利用斐波那契数列的递归关系进行建模和求解。
5. **生物学**:斐波那契数列描述了许多生物体的生长模式,如兔子繁殖、植物叶序等。
五、斐波那契数列在ACM-ICPC中的典型问题 在ACM-ICPC竞赛中,涉及斐波那契数列的问题形式多样,以下是一些典型问题:
1. **求第n个斐波那契数**:利用不同的算法(递归、动态规划、矩阵快速幂)来计算第n个斐波那契数。
2. **斐波那契数列的和**:计算斐波那契数列前n项的和,或者求解满足特定条件的斐波那契数列的子序列和。
3. **斐波那契数列的模运算**:计算斐波那契数列模某一数的余数,用于解决大数问题。
4. **斐波那契数列在格点路径中的应用**:通过斐波那契数列计算满足特定条件的路径数量。
5. **斐波那契数列的组合问题**:利用斐波那契数列解决组合数学中的问题,如不同的排列方式、分割方案等。 通过以上这些方法和应用,我们可以深入理解和高效解决涉及斐波那契数列的问题,从而在算法竞赛中取得更好的成绩。 希望这篇博客能够帮助读者更好地理解斐波那契数列及其在ACM-ICPC中的应用。如有任何问题或建议,欢迎留言交流。
一、斐波那契数列的定义
斐波那契数列(The Fibonacci sequence,OEIS A000045)的定义如下:
该数列的前几项如下:
二、卢卡斯数列
卢卡斯数列(The Lucas sequence,OEIS A000032)的定义如下:
该数列的前几项如下:
研究斐波那契数列,很多时候需要借助卢卡斯数列为工具。
三、斐波那契数列的通项公式
第 nnn 个斐波那契数可以在 Θ(n)\Theta (n) Θ(n) 的时间内使用递推公式计算。但我们仍有更快速的方法计算。
解析解
斐波那契数列的通项公式(Binet's Formula)如下:
这个公式可以很容易地用归纳法证明,当然也可以通过生成函数的概念推导,或者解一个方程得到。
由于公式分子的第二项总是小于 1,并且它以指数级的速度减小。因此我们可以把这个公式写成:
这里的中括号表示取离它最近的整数。
卢卡斯数列通项公式
我们有卢卡斯数列的通项公式:
与斐波那契数列非常相似。事实上有:
也就是说,LnL_nLn 和 FnF_nFn 恰好构成 (1+52)n\left(\frac{1 + \sqrt{5}}{2}\right)^n(21+5)n 二项式展开再合并同类项后的分子系数。
四、斐波那契数列的矩阵形式
斐波那契数列的递推可以用矩阵乘法的形式表达:
于是我们可以用矩阵乘法在 Θ(logn)\Theta(\log n) Θ(logn) 的时间内计算斐波那契数列。
五、快速倍增法
使用上面的方法我们可以得到以下等式:
通过这样的快速计算方法,可以高效地计算斐波那契数列。以下是代码示例,返回值是一个二元组
pair<int, int> fib(int n) {
if (n == 0) return {0, 1};
auto p = fib(n >> 1);
int c = p.first * (2 * p.second - p.first);
int d = p.first * p.first + p.second * p.second;
if (n & 1)
return {d, c + d};
else
return {c, d};
}
六、斐波那契数列的性质
斐波那契数列拥有许多有趣的性质,这里列举出一部分简单的性质:
-
卡西尼性质(Cassini's identity):
-
附加性质:
-
GCD 性质:
-
以斐波那契数列相邻两项作为输入会使欧几里德算法达到最坏复杂度。
七、斐波那契数列与卢卡斯数列的关系
关于卢卡斯数列与斐波那契数列的等式,与三角函数公式具有很高的相似性。例如:
类似于:
以及:
类似于:
因此,卢卡斯数列与余弦函数相似,而斐波那契数列与正弦函数相似。根据:
可以得到两下标之和的等式:
这也是一种快速倍增下标的方法。也可以仿照三角函数的公式,推理出更多有关卢卡斯数列与斐波那契数列的相应等式。
八、斐波那契编码
可以利用斐波那契数列为正整数编码。根据齐肯多夫定理,任何自然数 nnn 可以被唯一地表示成一些斐波那契数的和:
并且 k1≥k2+2, k2≥k3+2, …, kr≥2k_1 \ge k_2 + 2, \, k_2 \ge k_3 + 2, \, \ldots, \, k_r \ge 2k1≥k2+2,k2≥k3+2,…,kr≥2(即不能使用两个相邻的斐波那契数)。
编码过程可以使用贪心算法解决:
- 从大到小枚举斐波那契数 FiF_iFi,直到 Fi≤nF_i \le nFi≤n。
- 把 nnn 减掉 FiF_iFi,在编码的 i−2i-2i−2 的位置上放一个 1(编码从左到右以 0 为起点)。
- 如果 nnn 为正,回到步骤 1。
- 最后在编码末位添加一个 1,表示编码的结束位置。
解码过程同理,先删掉末位的 1,对于编码为 1 的位置 iii(编码从左到右以 0 为起点),累加一个 Fi+2F_{i+2}Fi+2 到答案。最后的答案就是原数字。
九、模意义下周期性
考虑模 ppp 意义下的斐波那契数列,可以容易地使用抽屉原理证明,该数列是有周期性的。考虑模意义下前 p2+1p^2+1p2+1 个斐波那契数对(两个相邻数配对):
由于 ppp 的剩余系大小为 ppp,在前 p2+1p^2+1p2+1 个数对中必有两个相同的数对,那么他们就是周期性的。
十、皮萨诺周期
模 mmm 意义下斐波那契数列的最小正周期被称为皮萨诺周期(Pisano periods, OEIS A001175)。
皮萨诺周期总是不超过 6m6m6m,且只有在满足 m=2×5km=2 \times 5^km=2×5k 的形式时才取到等号。
容易验证,斐波那契数模 2 的最小正周期是 3,模 5 的最小正周期是 20。
当需要计算第 nnn 项斐波那契数模 mmm 的值的时候,如果 nnn 非常大,就需要计算斐波那契数模 mmm 的周期。只需要计算周期,不一定是最小正周期。
如果 aaa 与 bbb 互素,ababab 的皮萨诺周期就是 aaa 的皮萨诺周期与 bbb 的皮萨诺周期的最小公倍数。
结论 1
对于奇素数 p≡1,4(mod5)p \equiv 1, 4 \pmod{5}p≡1,4(mod5),p−1p-1p−1 是斐波那契数模 ppp 的周期。即,奇素数 ppp 的皮萨诺周期整除 p−1p-1p−1。
结论 2
对于奇素数 p≡2,3(mod5)p \equiv 2, 3 \pmod{5}p≡2,3(mod5),2p+22p+22p+2 是斐波那契数模 ppp 的周期。即,奇素数 ppp 的皮萨诺周期整除 2p+22p+22p+2。
结论 3
对于素数 ppp,MMM 是斐波那契数模 pk−1p^{k-1}pk−1 的周期,等价于 MpMpMp 是斐波那契数模 pkp^kpk 的周期。特别地,MMM 是模 pk−1p^{k-1}pk−1 的皮萨诺周期,等价于 MpMpMp 是模 pkp^kpk 的皮萨诺周期。
十一、习题
- SPOJ - Euclid Algorithm Revisited
- SPOJ - Fibonacci Sum
- HackerRank - Is Fibo
- Project Euler - Even Fibonacci numbers
- 洛谷 P4000 斐波那契数列
通过这些习题,可以更好地理解和应用斐波那契数列及其相关性质。希望这篇博客能够帮助读者更好地掌握斐波那契数列在组合数学和算法竞赛中的应用。如有任何问题或建议,欢迎留言交流。