对于一个运算:求a的n次幂,我们知道最暴力的方法就是开一个变量ans,赋值为1,然后对ans乘以a n次,就可以得到答案。但是如果这个n很大,时间复杂度就会变高,这事我们就会想要优化时间复杂度,于是就引出了快速幂。快速幂的原理就是对n就行二进制拆分,假如n=10,二进制是1010,那么a^2*a^8就可以得到a^10,这样我们就不在一个一个的乘,而是先让a自乘一次得到a^2,把a^2乘给ans,然后再让a自乘两次得到a^8(a^2*a^2=a^4,a^4*a^4=a^8),再把a^8乘给ans就可以得到a^10了,这样我们的复杂度就降到了logn级别。而具体实现时就是判断n的最后一位如果是1就把当前自乘出来的a乘给ans,否则a直接自乘然后n除以2
模板:
while(n) { if(p&1)ans=ans*a%k;//实际运算时数很大,都会对一个数进行取模 a=a*a%k; //因为a本身就是a^1,所以第一次运算时我们先判断有没有a^1有的话直接乘上去再自乘,自乘完毕就变成了n^2,所以下一次循环还是要先判断有没有这一位,有的话先乘上去在自乘,每一次都是这样 n>>=1; }
矩阵快速幂和这个的原理是一样的,对n进行二进制拆分,不同的是每次的自乘和往ans上乘的运算需要自己来写,模板
#include<iostream> #include<cstdio> #define ll long long using namespace std; const int mod=1e9+7; const int maxn=105; int n; ll k; int a[maxn][maxn]; int ans[maxn][maxn],tmp[maxn][maxn]; void chengans() { for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) for(int k=1;k<=n;++k) { tmp[i][j]=(tmp[i][j]+(ll)a[i][k]*ans[k][j]%mod)%mod; } for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) ans[i][j]=tmp[i][j],tmp[i][j]=0; } void zicheng() { for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) for(int k=1;k<=n;++k) tmp[i][j]=(tmp[i][j]+(ll)a[i][k]*a[k][j]%mod)%mod; for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) a[i][j]=tmp[i][j],tmp[i][j]=0; } int main() { scanf("%d%lld",&n,&k); for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) scanf("%d",&a[i][j]),ans[i][j]=a[i][j]; k--;//矩阵的运算有一点点特殊,ans数组一开始得赋值成原始数组,这样就相当于一开始就已经乘了一次原始矩阵了,所以指数减一再去运算才是所求答案 while(k) { if(k&1)chengans(); zicheng (); k>>=1; } for(int i=1;i<=n;++i) { for(int j=1;j<=n;++j) printf("%d ",ans[i][j]); printf(" "); } return 0; }