快速幂求解斐波那契数列
斐波那契数列
斐波那契数列是很经典也很简单的一条题目。其满足:
F n = { 1 ( n ≤ 2 ) F n − 1 + F n − 2 ( n ≥ 3 ) F_{n}= \begin{cases}1 & (n \leq 2) \\ F_{n-1}+F_{n-2} & (n \geq 3)\end{cases} Fn={1Fn−1+Fn−2(n≤2)(n≥3)
请求出 F n m o d 1 0 9 + 7 F_{n} \bmod 10^{9}+7 Fnmod109+7的值。
递归和顺序求解
最简单的方法便是递归和顺序求解。递归的时间复杂度为 O ( 2 n ) O(2^n) O(2n),顺序求解的复杂度为 O ( n ) O(n) O(n)。这里不再贴代码了。
快速幂
那有没有比 O ( n ) O(n) O(n)更快的方法呢。是有的。快速幂的最基础应用便是求一个数的 n n n次方。比如我们要求 1 1 10 11^{10} 1110。如果一次一次乘,那么需要九次乘法。如果先算11的五次方,再求平方,那么便需要五次乘法。那先计算 11 ∗ 11 = 121 11*11=121 11∗11=121,那么11的五次方便是 121 ∗ 121 ∗ 11 121*121*11 121∗121∗11,再平方,最后一共用了四次乘法。有没有发现,拆解的越多,乘法的次数就越少,那么采用二分的思想,便可实现 O ( l o g 2 n ) O(log_2n) O(log2n)时间复杂度的求幂次方。
刚才的二分想法的递归方程不难理解,如下:
a n = { a n − 1 ⋅ a , if n is odd a n 2 ⋅ a n 2 , if n is even but not 0 1 , if n = 0 a^{n}= \begin{cases}a^{n-1} \cdot a, & \text { if } n \text { is odd } \\ a^{\frac{n}{2}} \cdot a^{\frac{n}{2}}, & \text { if } n \text { is even but not } 0 \\ 1, & \text { if } n=0\end{cases} an=⎩⎪⎨⎪⎧an−1⋅a,a2n⋅a2n,1, if n is odd if n is even but not 0 if n=0
代码也很简单:
int qpow(int a, int n)
{if (n == 0)return 1;else if (n % 2 == 1)return qpow(a, n - 1) * a;else{int temp = qpow(a, n / 2);return temp * temp;}
}
需要注意的是,这里的temp变量是需要的,如果直接“return qpow(a, n/2)*qpow(a, n/2)”,那其实会计算两次qpow(a, n/2),时间复杂度退化到了 O ( n ) O(n) O(n)。
递归会有额外空间开销,我们可以用循环的方式写,代码如下:
int qpow(int a, int n){int ans = 0;while (n){if (n & 1){ans *= a; }a *= 1;n >> 1;}return ans;
}
按照上面 1 1 10 11^{10} 1110的例子,这个循环就是将其拆成 1 1 10 = 1 1 8 + 1 1 2 11^{10} = 11^8 + 11^2 1110=118+112。通过不断的“n >> 1”来获取当前n二进制最后一个1。
快速幂求解斐波那契
下面就是最关键的部分了。
设矩阵 A = [ 0 1 1 1 ] A=\left[\begin{array}{ll}0 & 1 \\ 1 & 1\end{array}\right] A=[0111],有 A [ F n F n + 1 ] = [ F n + 1 F n + F n + 1 ] = [ F n + 1 F n + 2 ] A\left[\begin{array}{c}F_{n} \\ F_{n+1}\end{array}\right]=\left[\begin{array}{c}F_{n+1} \\ F_{n}+F_{n+1}\end{array}\right]=\left[\begin{array}{c}F_{n+1} \\ F_{n+2}\end{array}\right] A[FnFn+1]=[Fn+1Fn+Fn+1]=[Fn+1Fn+2],那么:
[ F n F n + 1 ] = A [ F n − 1 F n ] = A 2 [ F n − 2 F n − 1 ] = … = A n − 1 [ F 1 F 2 ] = A n − 1 [ 1 1 ] \begin{aligned} {\left[\begin{array}{c} F_{n} \\ F_{n+1} \end{array}\right] } &=A\left[\begin{array}{c} F_{n-1} \\ F_{n} \end{array}\right] \\ &=A^{2}\left[\begin{array}{l} F_{n-2} \\ F_{n-1} \end{array}\right] \\ &=\ldots \\ &=A^{n-1}\left[\begin{array}{l} F_{1} \\ F_{2} \end{array}\right] \\ &=A^{n-1}\left[\begin{array}{l} 1 \\ 1 \end{array}\right] \end{aligned} [FnFn+1]=A[Fn−1Fn]=A2[Fn−2Fn−1]=…=An−1[F1F2]=An−1[11]
原来的求第n个斐波那契数列的值,变成了矩阵的n-1次方。代码如下:
#include <iostream>
using namespace std;
typedef long long ll; //由于数可能很大,所以采用long long。
const ll MOD = 1000000007;struct matrix
{ll a1, a2, b1, b2;matrix(ll a1, ll a2, ll b1, ll b2) : a1(a1), a2(a2), b1(b1), b2(b2) {}matrix operator * (const matrix& y) //重载*,适应矩阵乘法{matrix ans((a1 * y.a1 + a2 * y.b1) % MOD,(a1 * y.a2 + a2 * y.b2) % MOD,(b1 * y.a1 + b2 * y.b1) % MOD,(b1 * y.a2 + b2 * y.b2) % MOD); // 矩阵乘法,同时防止数过大,取余.return ans;}
};matrix qpow(matrix a, ll n) //套用快速幂模板
{matrix ans(1, 0, 0, 1); //单位矩阵while (n){if (n & 1)ans = ans * a;a = a * a;n >>= 1;}return ans;
}int main()
{ll n;matrix A(0, 1, 1, 1); //上述证明中的A矩阵。cin >> n;matrix ans = qpow(A, n - 1);cout << ans.a1 + ans.a2 % MOD;system("pause");return 0;
}
快速幂模板
斐波那契数列只是快速幂用于矩阵幂次方求解的应用,快速幂还是可以用于很多地方,都可以套用模板,代码如下:
//泛型的非递归快速幂
template <typename T>
T qpow(T a, ll n)
{T ans = 1; // 赋值为乘法单位元,可能要根据构造函数修改while (n){if (n & 1)ans = ans * a; // 这里就最好别用自乘了,不然重载完*还要重载*=,有点麻烦。n >>= 1;a = a * a;}return ans;
}
快速幂求解斐波那契数列相关推荐
- 矩阵快速幂及斐波那契数列模板
本篇博客先给出矩阵快速幂以及利用矩阵快速幂求斐波那契数列的模板,讲解待更新-- const int N=10; int tmp[N][N]; void multi(int a[][N],int b[] ...
- 矩阵快速幂求斐波那契数列(初学整理)
参考文章: http://blog.csdn.net/u013795055/article/details/38599321 http://blog.csdn.net/g_congratulation ...
- A - 【深蓝】教科书般的亵渎 (Gym - 102072A )(矩阵快速幂+计算斐波那契数列)
"现在给大家展示一波教科书般的亵渎" "扭了扭了" 炉石传说是一款比较火的卡牌游戏,不同的卡牌间可以打出许多不可思议的配合. 炉石传说的战斗大部分由随从来完成. ...
- 牛客18987 粉嘤花之恋(矩阵快速幂、斐波那契数列)
链接:https://ac.nowcoder.com/acm/problem/18987 来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32768K,其他语言65536 ...
- 矩阵快速幂及斐波那契数列
1.通用模板:矩阵快速幂 前几天写过一篇矩阵快速幂的一种解法,但是当时只是初学,所以用了当时我更好理解的方法去做.那个解法需要调用两个很相像的函数,而且容易造成紊乱,也不利于矩阵快速幂的推广,所以在观 ...
- 利用矩阵快速幂求斐波那契数列
我们知道如果用记忆化搜索逐项递推可以将复杂度降低到O(n),但是对于更大规模的输入,这个算法效率还是不够高,那么我们考虑更高效的算法: 二阶递推:f(n+2)=(1 1) f(n+1) f(n+1) ...
- 2017.3.25 矩阵快速幂 求斐波那契数列第n项
对于矩阵快速幂只要知道矩阵取模.乘法原理就完全可以手推 口诀:行 列 被计算的行列的交点是结果对应的位置: 剩下的就是推矩阵: 其实根据矩阵的方程意义就很好推了: 码: #includ ...
- 求解斐波那契数列复杂度分析
前言:斐波那契作为一个算法基础知识,大家一定要掌握,祝大家学得开心~ 什么是斐波那契数列(Fibonacci sequence)? 斐波那契数列(Fibonacci sequence),又称黄金分割数 ...
- C语言实现求解斐波那契数列的四种方法及优化处理(递归,迭代,特殊性质公式,矩阵快速幂)
众所周知,斐波那契数列是非常经典的一个数列,它的数学公式如下 为了便于观察,我们列出它的几项:0 1 1 2 3 5 8 13 21...... 下面我们将介绍四种方法来用C语言计算机 ...
最新文章
- SQL 2000 异数据库数据同步
- Word画线条5大技巧,简单实用!
- linux中的用户、群组和权限
- wxWidgets随笔(1)-hello,world
- 安装 CocoaPods Alcatraz
- vue样式绑定与事件处理器的基本使用
- linux内核的裁剪和移植实验,实验5 linux内核的裁剪移植.doc
- LINUX当前目录下的文件夹大小
- Robo 3T(Studio 3T)最新版安装教程
- 海思hi3516移动侦测代码并显示输出
- h5计时器(requestAnimationFrame)
- flutter 仿微信展开收起两种写法
- ipv4和ipv6连通性相关工具实例
- 计算机网络: 码元 波特 速率 带宽
- EEPROM 24C02 24C64误换Debug
- python中日期格式转换,计算单位天数时间差
- 是终点也是起点:你的恋爱目标是什么?
- Grab第一季营收2.28亿美元:亏损4.35亿美元 收窄35%
- Java之 public class 和 class 的区别
- 浙江省电力试验研究所打造IT运维精品工程