矩阵快速幂
在我们求一些递推式子是,如果一味的使用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]
在加上结合律我们就可以利用矩阵乘法就递推项了
再加上快速幂不就缩短时间了嘛

浙公网安备 33010602011771号