矩阵快速幂
在我们求一些递推式子是,如果一味的使用for可能在数据很大的时候就超时,所以引入矩阵快速幂
将递推关系隐藏在初始矩阵中,然后使用矩阵快速幂降低时间,就可求出
https://www.luogu.org/problem/P3390
/* Name: Copyright: Author: 流照君 Date: 2019/8/12 15:05:21 Description: */ #include <iostream> #include<string> #include <algorithm> #include <vector> #include<cstring> #define inf 100 using namespace std; typedef long long ll; const ll mod=1e9+7; ll n; struct matrix{ ll a[inf][inf];//构造函数 matrix(){ memset(a,0,sizeof(a)); } inline void bulid()//初始化 { for(int i=1;i<=n;i++) a[i][i]=1; } }; matrix ma,unit; matrix operator*(const matrix &x,const matrix &y)//重载运算符 { matrix ans; for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { ans.a[i][j]=(ans.a[i][j]+x.a[i][k]*y.a[k][j]%mod)%mod; } return ans; } matrix pow(matrix ma1,ll k) { matrix ans; ans.bulid(); do { if(k&1) ans=ans*ma1; ma1=ma1*ma1; k=k/2; }while(k); return ans; } int main(int argc, char** argv) { //freopen("in.txt", "r", stdin); //freopen("out.txt", "w", stdout); ll k; scanf("%lld %lld",&n,&k); for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { scanf("%lld",&ma.a[i][j]); } } unit.bulid(); matrix res=pow(ma,k); for(int i=1;i<=n;cout<<endl,++i) for(int j=1;j<=n;++j) printf("%lld ",res.a[i][j]); return 0; }
其中乘法可以不重载,而使用函数
转载一段话————————————————————————————————————————————————————————————————————
那么,矩阵乘法的优越性究竟体现在哪里呢。其实,矩阵乘法只是体现了我们从之前求的数到现在要求的数的递推过程,就是说矩阵乘法可以完成多个元素的递推。不过这个我们用普通的递推就可以实现的啊~~认真想想我们就能发现,我们在矩阵乘法的过程中把上见面的A矩阵自己相乘了很多遍。就是说,我们可以求A矩阵的幂最后乘上B矩阵,既然要求幂,矩阵乘法满足结合律,那么我们就可以用快速幂啦~~矩阵乘法的优越性就体现在这里:在递推过程变成不断乘以一个矩阵,然后用快速幂快速求得从第一个到第n个的递推式,这样子就可以在短时间内完成递推了。
哇塞,人类的智商啊~~让我们继续膜拜那些智商正无穷的大神吧,orz,orz…… 链接https://www.cnblogs.com/Konjakmoyu/p/4821044.html
——————————更新分界线——————————————————————————————————————————————————————
看MIT线性代数才真正理解矩阵快速幂 传送门
我们知道一个数列的递推公式 它可能不是一阶的,是很多阶的,所以这里有一个trick 就是将多阶的方程化为一阶方程组
比如:斐波那契数列 Fk+1=Fk+Fk-1;
我们可以改成AX 的矩阵形式 Fk+2=Fk+1+Fk;
Fk+1=Fk+1:
x=[Fk+1,Fk] 发现了吗?
于是我们找到了 [1,1;1,0]*[1,0]=[2,1] [1,1;1,0]*[Fk+1,Fk]=[Fk+2,Fk+1]
在加上结合律我们就可以利用矩阵乘法就递推项了
再加上快速幂不就缩短时间了嘛