今天来讲矩阵快速幂:
先卖个关子,对于一般的快速幂,我们是这样解决的:
eg:n19 mod k
我们知道,根据二进制
19(10)=10011(2)=(10000+10+1)(2)
所以可以将19二进制分解
这里引入res和ans和N三个变量。
令N=19,res=n,ans=1
10011末尾为1,所以将这个单独放入ans:ans=res*ans=n,接着将res平方:res=res*res=n2,将N右移一位:N>>=1。
1001:ans=res*ans=n3;res=res2=n4
100:末尾为0,不改变ans,但将res平方:res=n8
10:res=n16
1:ans=n3+16=19,;res=n32
最后我们得到结果。
时间复杂度:O(log₂N)。
上代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; ll n,k; ll quickpow(ll x,ll N){ ll res = x,ans = 1; while(N){ if(N & 1){ ans = ans * res; } res *= res; N >>= 1; } return ans; } int main(){ scanf("%lld%lld",&n,&k); printf("%lld\n",quickpow(n,k)); return 0; }
这是对于数字的快速幂,那么矩阵呢?
其实是一样的,我们将矩阵乘法代替乘号,ans变为单位矩阵I,其余不变。
上代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll mod=1e9+7; const ll maxn=110; ll n,k; struct matrix{ ll a[maxn][maxn]; void Empty(){ memset(a,0,sizeof(a)); } void One(){ Empty(); for(ll i=1;i<=n;i++) a[i][i]=1; } matrix operator *(matrix b){ matrix tmp; tmp.Empty(); for(ll i=1;i<=n;i++){ for(ll j=1;j<=n;j++){ for(ll q=1;q<=n;q++){ (tmp.a[i][j]+=a[i][q]*b.a[q][j]%mod)%=mod; } } } return tmp; } void out(){ for(ll i=1;i<=n;i++){ for(ll j=1;j<=n;j++){ printf("%lld ",a[i][j]%mod); } printf("\n"); } } }res,ans; void matrix_pow(ll N){ ans.One(); while(N){ if(N&1){ ans=ans*res; } res=res*res; N>>=1; } } int main(){ scanf("%lld%lld",&n,&k); for(ll i=1;i<=n;i++){ for(ll j=1;j<=n;j++){ scanf("%lld",&res.a[i][j]); } } matrix_pow(k); ans.out(); return 0; }
另外我们可以在矩阵中写一些函数便于操作,比如单位矩阵,矩阵乘法,矩阵清零,矩阵输出等。
你学会了吗?