矩阵快速幂

在我们求一些递推式子是,如果一味的使用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] 

 在加上结合律我们就可以利用矩阵乘法就递推项了

再加上快速幂不就缩短时间了嘛

posted @ 2019-08-12 17:28  流照君  阅读(221)  评论(0编辑  收藏  举报