先贴一个博主写的,偷个懒先:
快速幂的思路就是:
设A为矩阵,求A的N次方,N很大,1000000左右吧。。。
先看小一点的,A的9次方
A^9
= A*A*A*A*A*A*A*A*A 【一个一个乘,要乘9次】
= A*(A*A)*(A*A)*(A*A)*(A*A) 【保持格式的上下统一,所以加上这句】
= A*(A^2)^4 【A平方后,再四次方,还要乘上剩下的一个A,要乘6次】
= A*((A^2)^2)^2 【A平方后,再平方,再平方,还要乘上剩下的一个A,要乘4次】
也算是一种二分思想的应用吧,1000000次幂,暴力要乘1000000次,快速幂就只要(log2底1000000的对数) 次,大约20次。。。这。。。我没错吧。。。
但是因为是矩阵,矩阵乘法的复杂度是O(n^3)。。。所以快速幂的复杂度是
O( (logn)^3 * logn)
上代码!矩阵乘法的代码和上面一样,添加了mat_quick_index(MATRIX a,int N,int n)函数,主函数做了些许修改,以便检验。。。
---------------------
作者:番茄鱼片汤
来源:CSDN
原文:https://blog.csdn.net/u013795055/article/details/38599321
版权声明:本文为博主原创文章,转载请附上博文链接!
解释一下:就是说我要求A^9,我不用乘以9次,就好像问2^8=?,ok,我们先算2*2=4;然后就知道2^8=4^4;ok,再算下4*4=16;就知道 2^8=16^2,再算下16*16=256;所以我们算了log8=3次。所以问2^1024次方,不用循环1023次,只要10次ok。
矩阵相乘非常简单自行百度,写成代码不难,这里主要讲下在斐波那契数列之中的运用。
fi[i] = 1*fi[i-1]+1*fi[i-2]
fi[i-1] = 1*f[i-1] + 0*f[i-2];
转换成矩阵形式为:
帮解释一下昂:令 f(n) = { Fibonacci[n] , Fibonacci[n-1] } 要求f(5),就相当于求【矩阵】*f( 4 ),然后递归到 { f(1),f(0) };这里在反复乘以矩阵4次了。也就转换成矩阵幂了,如下:
矩阵乘以矩阵的代码很简单,主要讲下这里快速幂的核心代码。
//例如 5->进入if->N=2->N=1->进入if->N=0 结束 E为单位矩阵,N为指数
while(N>0)
{
if(N & 1) //与运算,即最低位为1即为奇数 执行
E=mat_multiply(E,a,n);
N>>=1; //右移,相当于除以二
a=mat_multiply(a,a,n);
}
这里有道斐波那契数列的题目非常经典,emmmm,有时间再补上吧!
http://www.51nod.com/Challenge/Problem.html#!#problemId=1242
千万千万要注意数据类型,我AC提交了四次才过,发现int n 没改 long long n;千万要小心!!!还有一点,是在矩阵乘法里面取模,第一次我在快速幂函数里面取模很多书通不过。知道的欢迎赐教,真心求知,emmm。
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
typedef struct
{
long long a[2][2];
} matrix;
//矩阵乘法
matrix P(long long a[2][2],long long b[2][2])
{
matrix c;
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
c.a[i][j]=0;
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
{
for(int k=0;k<2;k++)
{
c.a[i][j]=(c.a[i][j]+a[i][k]*b[k][j])%1000000009;
}
}
return c;
}
//矩阵快速幂
matrix Quick(matrix m,long long n)
{
matrix E;
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
if(i==j)
E.a[i][j]=1;
else
E.a[i][j]=0;
while(n>0)
{
if(n&1)
E=P(E.a,m.a);
n>>=1;
m=P(m.a,m.a);
}
return E;
}
int main()
{
matrix c,result;
c.a[1][0]=c.a[0][1]=c.a[0][0]=1;
c.a[1][1]=0;
long long n;
cin>>n;
result=Quick(c,n-1);
int fn=result.a[0][0];
cout<<fn;
return 0;
}
然后讲下矩阵快速幂最核心也是最难的部分,构造矩阵:
T * A(n-1)=A(n),T矩阵就是常数矩阵,而
构建矩阵递推的大致套路,一般An与A(n-1)都是按照原始递推式来构建的
给一些简单的递推式
1.f(n)=a*f(n-1)+b*f(n-2)+c;(a,b,c是常数)
2.f(n)=c^n-f(n-1) ;(c是常数)