快速幂
思想
我们要让计算机很快地计算出ab。
可以利用乘方的性质:axay=ax+y。
我们要求ab,可以将b拆成二进制数。比如b=(11)10=(1011)2,从左至右,每一个1,分别代表8,2,1,可以计算a11=a8a2a1 。
可以得出,如果b在二进制上的第n位是1,我们就把答案乘上对应的a2n。
在快速幂中,我们通过a的不断自乘,得到a1,a2,a4...,通过b的右移(>>),自右向左取得b的二进制位,用按位与运算(&)判断每一位是否为1。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| #include<iostream> using namespace std; typedef long long ll; ll quick_pow(ll a,ll b) { ll res=1; while(b) { if(b&1) res*=a; b>>=1; a=a*a; } return res; } int main() { ios::sync_with_stdio(false); ll a,b; cin>>a>>b; cout<<quick_pow(a,b); return 0; }
|
当然,一般会加上取余运算,计算$a^b mod $ p。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| #include<iostream> using namespace std; typedef long long ll; const ll p=1e9+7; ll quick_pow_mod(ll a,ll b) { ll res=1; while(b) { if(b&1) { res*=a; res%=p; } b>>=1; a=a*a; a%=p; } return res; } int main() { ios::sync_with_stdio(false); ll a,b; cin>>a>>b; cout<<quick_pow_mod(a,b); return 0; }
|
矩阵快速幂
含义
设A是一个n阶方阵,我们需要快速地计算Ab。
类比
矩阵快速幂与数的快速幂类似,只需要将快速幂代码的数,换成矩阵即可。
实现
①利用结构体定义矩阵,成员为一个n×n的二维数组。
②重载‘*’,实现矩阵的乘法${(AB)_{ij}} = \sum\limits_{k = 1}^n {{a_{ik}}{b_{kj}}} $。
③套快速幂的模板。
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| #include<iostream> #include<cstring> using namespace std; typedef long long ll; const int N=100; ll n,b; struct matrix { ll m[N][N]; matrix() { memset(m,0,sizeof(m)); } }; matrix operator *(const matrix &x,const matrix &y) { matrix res; int i,j,k; for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { for(k=1;k<=n;k++) { res.m[i][j]+=x.m[i][k]*y.m[k][j]; } } } return res; } matrix quick_matrix_pow_mod(matrix a,ll b) { matrix res; int i; for(i=1;i<=n;i++) res.m[i][i]=1; while(b) { if(b&1) res=res*a; a=a*a; b>>=1; } return res; } int main() { ios::sync_with_stdio(false); cin>>n>>b; int i,j; matrix a; for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { cin>>a.m[i][j]; } } matrix ans=quick_matrix_pow_mod(a,b); for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { cout<<ans.m[i][j]; if(j<n) cout<<' '; } cout<<endl; } return 0; }
|
当然,一般会要求对矩阵的每一个元素取余,只需要在重载‘*’时对元素取余即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| #include<iostream> #include<cstring> using namespace std; typedef long long ll; const int N=100; const ll p=1e9+7; ll n,b; struct matrix { ll m[N][N]; matrix() { memset(m,0,sizeof(m)); } }; matrix operator *(const matrix &x,const matrix &y) { matrix res; int i,j,k; for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { for(k=1;k<=n;k++) { res.m[i][j]+=x.m[i][k]*y.m[k][j]; res.m[i][j]%=p; } } } return res; } matrix quick_matrix_pow_mod(matrix a,ll b) { matrix res; int i; for(i=1;i<=n;i++) res.m[i][i]=1; while(b) { if(b&1) res=res*a; a=a*a; b>>=1; } return res; } int main() { ios::sync_with_stdio(false); cin>>n>>b; int i,j; matrix a; for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { cin>>a.m[i][j]; } } matrix ans=quick_matrix_pow_mod(a,b); for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { cout<<ans.m[i][j]; if(j<n) cout<<' '; } cout<<endl; } return 0; }
|
矩阵加速数列递推 (e.g. Fibonacci Sequence)
矩阵的递推思想
设Fibonacci Sequence的第n项为fn,f0=0,f1=1,那么有
fn=fn−1×1+fn−2×1,fn−1=fn−1×1+fn−2×0(n⩾2)
可以写成矩阵的乘法
令,于是可得
而An可由矩阵快速幂得到, 最后利用矩阵乘法定义得到fn=A21n,于是就这样在O(logn)的时间实现了数列递推。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| #include<iostream> #include<cstring> using namespace std; typedef long long ll; const int N=100; const ll p=1e9+7; const int n=2; struct matrix { ll m[N][N]; matrix() { memset(m,0,sizeof(m)); } }; matrix operator *(const matrix &x,const matrix &y) { matrix res; int i,j,k; for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { for(k=1;k<=n;k++) { res.m[i][j]+=x.m[i][k]*y.m[k][j]; res.m[i][j]%=p; } } } return res; } matrix quick_matrix_pow(matrix a,ll b) { matrix res; int i; for(i=1;i<=n;i++) res.m[i][i]=1; while(b) { if(b&1) res=res*a; a=a*a; b>>=1; } return res; } int main() { ios::sync_with_stdio(false); int k; cin>>k; int i,j; matrix a; a.m[1][1]=a.m[1][2]=a.m[2][1]=1; a.m[2][2]=0; matrix ans=quick_matrix_pow(a,k); cout<<ans.m[2][1]%p; return 0; }
|