斐波那契数列的第 n 项 mod 1000000007(矩阵乘法)
2016-05-16 22:11
387 查看
矩阵快速幂:
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) % 1000000007的结果即可。
引例 :求斐波那契数列的第 n 项 mod
1000000007 的值, n <= 10 18 。
分析 :斐波那契数列的递推式为 f(n) = f(n-1)+f(n-2) ,直接循环求出 f(n) 的时间复杂度是 O(n) ,对于题目中的数据范围显然无法承受。很明显我们需要对数级别的算法。由于 f(n) = 1*f(n-1)
+ 1*f(n-2) 这样的形式很类似于矩阵的乘法,所以我们可以先把这个问题复杂化一下,将递推求解 f(n) 与 f(n-1) 的过程看作是某两个矩阵相乘的结果,式子如下:
即:
所以我们只要不断地乘以上面式子中的第二个矩阵(也就是第二个矩阵的幂)就能够不断递推得到 f(n) 。但是这样于解题没有丝毫益处,反而使得常数变得更大(矩阵乘法的复杂度为立方级别)。所以我们就要利用矩阵乘法的一条重要性质:结合律。即矩阵 (A*B)*C = A*(B*C) ,证明过程可参见 2008 年国家集训队俞华程的论文。
有了结合律我们就可以用快速幂计算矩阵的幂,问题的复杂度顺利降到了 O(logn) 。
代码:
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) % 1000000007的结果即可。
引例 :求斐波那契数列的第 n 项 mod
1000000007 的值, n <= 10 18 。
分析 :斐波那契数列的递推式为 f(n) = f(n-1)+f(n-2) ,直接循环求出 f(n) 的时间复杂度是 O(n) ,对于题目中的数据范围显然无法承受。很明显我们需要对数级别的算法。由于 f(n) = 1*f(n-1)
+ 1*f(n-2) 这样的形式很类似于矩阵的乘法,所以我们可以先把这个问题复杂化一下,将递推求解 f(n) 与 f(n-1) 的过程看作是某两个矩阵相乘的结果,式子如下:
即:
所以我们只要不断地乘以上面式子中的第二个矩阵(也就是第二个矩阵的幂)就能够不断递推得到 f(n) 。但是这样于解题没有丝毫益处,反而使得常数变得更大(矩阵乘法的复杂度为立方级别)。所以我们就要利用矩阵乘法的一条重要性质:结合律。即矩阵 (A*B)*C = A*(B*C) ,证明过程可参见 2008 年国家集训队俞华程的论文。
有了结合律我们就可以用快速幂计算矩阵的幂,问题的复杂度顺利降到了 O(logn) 。
代码:
#include<iostream> #include<memory.h> #include<cstdlib> #include<cstdio> #include<cmath> #include<cstring> #include<string> #include<cstdlib> #include<iomanip> #include<vector> #include<list> #include<map> #include<algorithm> typedef long long LL; const LL maxn=1000+10; const LL mod=1000000007; const int N=2; using namespace std; struct Matrix { LL m ; }; Matrix A= { 1,1, 1,0 }; Matrix I= { 1,0, 0,1 }; Matrix multi(Matrix a,Matrix b) { Matrix c; for(int i=0;i<N;i++) { for(int j=0;j<N;j++) { c.m[i][j]=0; for(int k=0;k<N;k++) c.m[i][j]+=a.m[i][k]*b.m[k][j]%mod; c.m[i][j]%=mod; } } return c; } Matrix power(Matrix A,int k) { Matrix ans=I,p=A; while(k) { if(k&1) { ans=multi(ans,p); k--; } k>>=1; p=multi(p,p); } return ans; } int main() { int n; while(~scanf("%d",&n)) { Matrix ans =power(A,n-1); printf("%lld\n",ans,m[0][0]); } return 0; }
相关文章推荐
- android Callable Future FutureTask 解析
- 基于UDP协议的socket编程
- 兰顿蚂蚁
- hihocoder1059 String Matching Content Length(带长度条件的最长公共子序列)
- Modern UI for WPF 初接触
- cvCanny函数源码解析
- POJ 1556 The Doors(点到线段的距离+最短路)
- JavaScript的无阻塞加载
- HTML5框架、背景和实体
- HDU 5683 zxa and xor (模拟)
- 软件工程(十二)
- Objective-C Runtime Programming Guide 中文翻译
- Android wpa_supplcant 之--配置文件
- 数据结构实验之链表六:有序链表的建立
- Flea travel
- Java Web系统常用的第三方接口
- Centos7 关闭防火墙设置
- MPI发送接收例子
- linux corosync+pacemaker+drbd+mysql配置安装详解
- nodejs 小工具——supervisor