首先斐波那契数列的通式是:
我们要求出 \(f[n]\) 就需要枚举,时间复杂度为 \(O(n)\)
若用矩阵乘法和快速幂,就可达到 \(O(logn)\)
原理:\(f[i]\) 受到前两项的影响,那么可以设置一个 \(1\times2\) 的矩阵,原因是若所求受到的影响为 \(n\) 个变量,则可以设置一个 \(1\times n\)的矩阵转移,即:
其次,利用矩阵乘法就要保证 \(f[i]\) 运算后是往后移一位的,与之相乘的一定是一个\(2\times 2\) 的矩阵,怎么找呢?
我们不妨这么设
因为两者相乘后我们得到的答案为
所以可以列出方程式
我们可以有合并同类项可得二式的解为 \(b=1,d=0\)
而一式可以将右侧的 \(f[i+1]\) 拆分成 \(f[i]+f[i-1]\) 再进行合并同类项
得:\(a=1,c=1\)
综上所述,我们的相乘矩阵为:
那么式子就可以推导为
化简得
因此我们可以用矩阵快速幂,在 \(O(logn)\) 级别求出
太妙了~
struct matrix
{
int n,m;
int z[10][10];
matrix(){
n=m=0;
memset(z,0,sizeof(z));
}
};
matrix operator*(const matrix &m1, const matrix &m2)
{
matrix m3;
m3.n = m1.n;
m3.m = m2.m;//矩阵原理
for (int i=1;i<=m3.n;i++)
//乘法分配律,乘法交换律,思考?????????????????????????
for (int k=1;k<=m1.m;k++)
for (int j=1;j<=m3.m;j++)
m3.z[i][j] += m1.z[i][k] * m2.z[k][j];
return m3;//矩阵乘法
}
matrix ksm(matrix m, int n)
{
if (n==0){//当n==0时存在一个特殊的矩阵上述会给出
matrix z;
z.n=z.m=m.n;
for (int i=1;i<=z.n;i++)
z.z[i][i]=1;//特殊的快速幂即只有对角线为1,其余全是0
return z;
}
matrix z=ksm(m,n/2);
z=z*z;
if (n%2==1) z=z*m;//利用承载运算符,所以乘的时候直接就是矩阵乘法
return z;
}
int main()
{
scanf("%d",&n);
matrix m1;
m1.n =1;m1.m=2;
m1.z[1][1]=1;m1.z[1][2]=0;
matrix m2;
m2.n=m2.m=2;
m2.z[1][1]=1; m2.z[1][2]=1;
m2.z[2][1]=1; m2.z[2][2]=0;
m1 = m1 * ksm(m2, n);
printf("%d\n"m1.z[1][2]);
}
原文:https://www.cnblogs.com/lToZvTe/p/14407155.html