矩阵快速幂的用法
要讲矩阵快速幂,就要先了解快速幂是个啥玩意。比如说我们要求2的127次方,容易想到的做法是乘127次,也就是O(n)的时间复杂度,那么有没有效率更高的算法呢?答案是有的,那就是快速幂。
首先将127写成二进制串(1111111),所以就可以把2^127写成
2^64 × 2^32 × 2^16 × 2^8 × 2^4 × 2^2 × 2^1
可以看到这个式子从右到左,左边的因子是右边的因子的平方,这不就很方便我们列举这些因子了吗,下一个就是上一个的平方,剩下的工作就是选择那些我们需要的因子,这里举的是一个特殊的例子(2的127次方包含了所有因子)。
如果我们要求的是2的100次方,100可以写成1100100。首先初始化 ans = 1 ,因子x = 2,
检验最后一位为0,ans 不变(不存在因子2^1),x = x^2 = 2^2(下一个因子是上一个的平方),
检验倒数第二位为0,ans不变,x = x^2 = 2^4,
检验倒数第三位为1,ans = ans * 2^4 (存在因子2^4),x = x^2 = 2^8,
…
检验第三位为0,ans不变,x = x^2 = 2^32,
检验第二位为1,ans = ans * 2^32 ,x = x^2 = 2^64,
检验第一位为1,ans = ans * 2^64,x = x^2 = 2^128。
代码如下
int fast_pow(int x,int n)
{
int ans=1;
while(n!=0)
{
if(n & 1)
ans=ans*x;
x=x*x;
n=n>>1;
}
return ans;
}
了解了快速幂后,矩阵的快速幂就很容易了,就是把 x 换成矩阵就好了
int N = 10;
typedef long long LL;
struct mat_{
LL m[N][N];
};
typedef mat_ mat;
mat mat_mul(mat A, mat B)
{
mat C;
memset(C.m, 0, sizeof(C.m));
for(int i=0; i<N; i++)
for(int j=0; j<N; j++)
for(int k=0; k<N; k++)
C.m[i][j]=(C.m[i][j] + (A.m[i][k] * B.m[k][j]) % MOD) % MOD;
return C;
}
mat mat_pow(mat A, int n)
{
mat ans;
for(int i=0; i<N; i++)
for(int j=0; j<N; j++)
if(i==j) ans.m[i][j]=1;
else ans.m[i][j]=0;
while(n != 0)
{
if(n & 1)
ans=mat_mul(ans, A);
A=mat_mul(A, A);
n >>= 1;
}
return ans;
}