51nod 巨大的斐波那契数列(矩阵快速幂),递推式优化的好模板!!!!!!!
2015-10-24 16:12
453 查看
斐波那契数列的定义如下:
F(0) = 0
F(1) = 1
F(n) = F(n - 1) + F(n - 2) (n >= 2)
(1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, ...)
给出n,求F(n),由于结果很大,输出F(n) % 1000000009的结果即可。
Input
Output
Input示例
Output示例
著作权归作者所有。
商业转载请联系作者获得授权,非商业转载请注明出处。
作者:王希
链接:http://www.zhihu.com/question/23582123/answer/40464211
来源:知乎
矩阵递推关系
学过代数的人可以看出,下面这个式子是成立的:
<img src="https://pic1.zhimg.com/d900e0509f9d056286ff9455e7706f90_b.jpg" data-rawwidth="284" data-rawheight="69" class="content_image" width="284">不停地利用这个式子迭代右边的列向量,会得到下面的式子:
不停地利用这个式子迭代右边的列向量,会得到下面的式子:
<img src="https://pic3.zhimg.com/c564ec78cf8008541bc1bbcfd4a70dea_b.jpg" data-rawwidth="270" data-rawheight="70" class="content_image" width="270">这样,问题就转化为如何计算这个矩阵的n次方了,可以采用快速幂的方法。
这样,问题就转化为如何计算这个矩阵的n次方了,可以采用快速幂的方法。快速幂_百度百科是利用结合律快速计算幂次的方法。比如我要计算,我们知道,而可以通过来计算,而可以通过计算,以此类推。通过这种方法,可以在O(lbn)的时间里计算出一个数的n次幂。快速幂的代码如下:
F(0) = 0
F(1) = 1
F(n) = F(n - 1) + F(n - 2) (n >= 2)
(1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, ...)
给出n,求F(n),由于结果很大,输出F(n) % 1000000009的结果即可。
Input
输入1个数n(1 <= n <= 10^18)。
Output
输出F(n) % 1000000009的结果。
Input示例
11
Output示例
89
著作权归作者所有。
商业转载请联系作者获得授权,非商业转载请注明出处。
作者:王希
链接:http://www.zhihu.com/question/23582123/answer/40464211
来源:知乎
矩阵递推关系
学过代数的人可以看出,下面这个式子是成立的:
<img src="https://pic1.zhimg.com/d900e0509f9d056286ff9455e7706f90_b.jpg" data-rawwidth="284" data-rawheight="69" class="content_image" width="284">不停地利用这个式子迭代右边的列向量,会得到下面的式子:
不停地利用这个式子迭代右边的列向量,会得到下面的式子:
<img src="https://pic3.zhimg.com/c564ec78cf8008541bc1bbcfd4a70dea_b.jpg" data-rawwidth="270" data-rawheight="70" class="content_image" width="270">这样,问题就转化为如何计算这个矩阵的n次方了,可以采用快速幂的方法。
这样,问题就转化为如何计算这个矩阵的n次方了,可以采用快速幂的方法。快速幂_百度百科是利用结合律快速计算幂次的方法。比如我要计算,我们知道,而可以通过来计算,而可以通过计算,以此类推。通过这种方法,可以在O(lbn)的时间里计算出一个数的n次幂。快速幂的代码如下:
#include <iostream> #include <algorithm> #include <cmath> #define MOD 1000000009 #define N 2 using namespace std; struct Matrix { long long v ; }; Matrix matrix_mul(Matrix A, Matrix B, long long m) { Matrix ans; for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { ans.v[i][j] = 0; for (int k = 0; k < N; k ++) { ans.v[i][j] += (A.v[i][k] * B.v[k][j]) % m; } ans.v[i][j] %= m; } } return ans; } Matrix matrix_pow(Matrix C, long long n, long long m) { Matrix ans = {1, 0, 0, 1}; while (n) { if (n & 1) ans = matrix_mul(ans, C, m); C = matrix_mul(C, C, m); n >>= 1; } return ans; } int main() { long long n; Matrix temp1 = {1, 1, 1, 0}, temp2 = {1, 0, 1, 0}; // temp2{f[2],0,f[1],0}!!!!! while (cin >> n) { if (n < 2) { cout << 1 << endl; continue; } Matrix res = matrix_pow(temp1, n - 2, MOD); res = matrix_mul(res, temp2, MOD); cout << res.v[0][0] << endl; } return 0; }
相关文章推荐
- TypeScript学习-TypeScript数据类型简介
- Action访问Servlet API的几种方式,其中方式三比较常用,下来是方式一,最后是方式二(实现接口的方式)
- c++读取lua中的table
- Android面试题及答案2
- A cycle was detected in the build path of project
- C语言中文件路径名的“双斜杠”和“单斜杠”的易错点(适用于C++和JAVA等语言)
- JavaScript中数组的合并以及排序实现示例
- JDBC和Hibernate的区别
- 单点登录SSO的实现原理
- OS X EI Capitan 10.11.1快速升级方法介绍
- css3动画
- 课堂作业之系统利益相关者分析
- 手把手教你自定义attr
- 习题四第10题
- leetcode 189 Rotate Array
- Struts2接收参数的几种方式
- rockchip平台镜像烧写方式
- C# 连接自动拨号与断开分析
- boot.img的修改
- 编程之法之-字符串的旋转