嗯~ 今天总结一下快速幂的知识点
1.首先讲一下矩阵相乘
矩阵A与矩阵B相乘的前提条件:A矩阵的列必须和矩阵B的行相等。若A矩阵是m*p的矩阵,那么B矩阵必定是p*n的矩阵,最后A*B得到的矩阵C是m*n的矩阵。
其中矩阵C的第 i 行第 j 列元素是矩阵A的第 i 行元素与矩阵B的第j列相应元素的乘积之和。
举个栗子,如下所示:
2.整数快速幂
为了引出快速幂的好处,我们根据下面的栗子来认识一下快速幂算法的优化之处。
例如我们要求x^8,暴力的方法就是用x乘7次,但是如果我们这样算:(x*x)(x*x)(x*x)(x*x), 那我们就只用算出x*x,然后用x*x乘3次就可以得到结果,这样总共就乘了4次,所以我们就引入快速幂的算法。
由我们引进了2进制的知识。
由于如果幂太小的话,就体现不出快速幂算法的优化了,所以这里我们用x^21做栗子,
,(21的二进制是10101)。
由上面可以看出二进制位中如果是1的话就乘,如果是0的话就不用乘,
下面是用整数快速幂求( x^n)%k 的核心代码:
int QuickPow(int x,int n,int k)
{
int ans = 1;
while(n)
{
if(n&1)///&运算,如果k的二进制中最后一位是1的话结果就是1,如果是0的话结果就是0
ans = (ans * x) % k;
x = (x * x) % k;
n = n >> 1;///k的二进制数右移一位
}
return ans;
}
(补充一下&运算的知识)如下图.
3.矩阵快速幂
有了整数快速幂的基础之后,矩阵快速幂就简单多了。
下面是用矩阵快速幂求n*n的矩阵S^k的核心代码:
///矩阵类结构体
struct matrix
{
int m[20][20];
}S;
matrix matrix_multiply(matrix A,matrix B)///求矩阵的乘积
{
matrix C;
for(int i = 1; i <= n; i++)///初始化为0矩阵
{
for(int j = 1; j <= n; j++)
C.m[i][j] = 0;
}
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n; j++)
{
for(int k = 1; k <= n; k++)
C.m[i][j] = (C.m[i][j] +A.m[i][k]*B.m[k][j]) % Mod;
}
}
return C;
}
matrix QuickPow(int k)
{
matrix ans;///ans初始化为单位矩阵
for(int i = 1; i <= n; i++)///单位矩阵乘任何矩阵都等于矩阵本身
{
for(int j = 1; j <= n; j++)
ans.m[i][j] = 0;
ans.m[i][i] = 1;
}
while(k)
{
if(k&1)
ans = matrix_multiply(ans,S);
S = matrix_multiply(S,S);
k = k >> 1;
}
return ans;
}