参考学习:
https://blog.csdn.net/acecandy/article/details/83864763
斐波拉契数列 矩阵快速幂
题目描述
PIPI今天刚刚学习了斐波拉契数列:
F(0) = 1
F(1) = 1
F(n) = F(n-1) + F(n-2) (n>1)
现在PIPI想知道斐波拉契数列的第 k 项,胖虎能够告诉PIPI吗?
由于结果很大,输出F(k)对p取模的结果即可~
p = 109+7
输入
输入包含多组测试用例。
每组测试用例包含一个正整数 k (1<=k<=1010)
输出
对于每组样例,输出F(k)%p
样例输入
1
2
3
4
5
样例输出
1
2
3
5
8
默认初始矩阵单位阵:
1次幂矩阵:
通过计算幂矩阵的n-1次,从而得出fn的值。
求这种问题,当然不是一直for循环乘上去这么蠢的方法。
假如我们需要求,可以把63分解为32+16+8+4+2+1。
for累加需要计算62次乘法,而2进制分解只要6次乘法,5次加法。
不管指数是多少,都可以将其分解为 2 的倍数的和。因为任何整数都能够写成 2 进制的形式,2进制可以表示任何一个整数。这就是关于求次方的快速幂算法。
如15 = 1111(2),求。 sum =1, an=m; 记x=15
第一步,1111&1 =1(真,按位与) sum=sum*an=m, 1111>>1(左移1位,除2),an = m*m; x=111(2) =7
第二步,111&1 =1, sum=sum*an = , 111>>1, an =, x=11(2) =3
第三步,11&1=1,sum =sum*an = , 11>>1,an =,x=1(2)=1
第三步,1&1=1,sum = sum*an = ,1>>1,x=0,退出循环。即求出。
参考代码如下:
#include<iostream>
#include<cstring>
using namespace std;
#define p 1000000007
int main(){
long long k;
while(scanf("%d",&k)!=EOF){
if(k==0 || k==1)
{
printf("1\n");
continue;
}
long long mar[2][2] ={1,1,1,0}; //1次幂
long long res[2][2] ={1,0,0,1}; //单位阵
k = k-1;
while(k>0){
if(k&1){
long long temp[2][2];
temp[0][0] = (res[0][0]*mar[0][0] +res[0][1] *mar[1][0])%p;
temp[0][1] = (res[0][0]*mar[0][1] +res[0][1] *mar[1][1])%p;
temp[1][0] = (res[1][0]*mar[0][0] +res[1][1] *mar[1][0])%p;
temp[1][1] = (res[1][0]*mar[0][1] +res[1][1] *mar[1][1])%p;
memcpy(res,temp,sizeof(temp));
}
k = k>>1;
long long temp[2][2];
temp[0][0] = (mar[0][0]*mar[0][0] +mar[0][1] *mar[1][0])%p;
temp[0][1] = (mar[0][0]*mar[0][1] +mar[0][1] *mar[1][1])%p;
temp[1][0] = (mar[1][0]*mar[0][0] +mar[1][1] *mar[1][0])%p;
temp[1][1] = (mar[1][0]*mar[0][1] +mar[1][1] *mar[1][1])%p;
memcpy(mar,temp,sizeof(temp));
}
long long sum;
sum = res[0][0] + res[0][1];
printf("%lld\n",sum%p);
}
return 0;
}