矩阵快速幂1

关于快速幂

可参考以下博客:
快速幂算法

关于构造矩阵

可参考以下两篇博客:
矩阵构造方法
根据递推公式构造系数矩阵用于快速幂

以斐波那契数列为例 f [ n ] = f [ n − 1 ] + f [ n − 2 ] ( f [ 1 ] = f [ 2 ] = 1 ) f[n]=f[n-1]+f[n-2]\quad (f[1]=f[2]=1) f[n]=f[n1]+f[n2](f[1]=f[2]=1)
我们可得
f [ n ] = 1 × f [ n − 1 ] + 1 × f [ n − 2 ] f[n]=1\times f[n-1]+1\times f[n-2] f[n]=1×f[n1]+1×f[n2]
f [ n − 1 ] = 1 × f [ n − 1 ] + 0 × f [ n − 2 ] f[n-1]=1\times f[n-1]+0\times f[n-2] f[n1]=1×f[n1]+0×f[n2]
进行矩阵构造
[ f [ n ] f [ n − 1 ] ] = [ 1 1 1 0 ] × [ f [ n − 1 ] f [ n − 2 ] ] \left[ \begin{matrix} f[n] \\ f[n-1] \\ \end{matrix} \right]=\left[ \begin{matrix} 1 &1 \\ 1 & 0 \\ \end{matrix} \right]\times \left[ \begin{matrix} f[n-1] \\ f[n-2] \\ \end{matrix} \right] [f[n]f[n1]]=[1110]×[f[n1]f[n2]]
× \times ×左面矩阵为 f [ n ] , f [ n − 1 ] f[n],f[n-1] f[n],f[n1]等式右侧系数,右侧为等号右侧的项,我们可使用以上式子进行递推,设 × \times ×左边矩阵为 A A A,则最后可得 f [ n ] = A n − 2 [ f [ 2 ] f [ 1 ] ] f[n]=A^{n-2}\left[ \begin{matrix} f[2] \\ f[1] \\ \end{matrix} \right] f[n]=An2[f[2]f[1]]
A n − 2 A^{n-2} An2 B B B,则 f [ n ] = B 1   1 + B 1   2 f[n]=B_{1\,1}+B_{1\,2} f[n]=B11+B12
矩阵快速幂中,最核心的是计算出基础矩阵A。要满足K阶常系数线性递推关系
以下为两道例题:

P3390 【模板】矩阵快速幂

题目链接

P3390 【模板】矩阵快速幂

代码
#include <iostream>
#include <cstdio>
#define ll long long
using namespace std;

const int maxn=105,p=1e9+7 ;
int n;
ll k ;
struct ymatrix
{
	ll a[maxn][maxn] ;
}A ;

inline ll read()
{
	ll x=0,f=1;char c=getchar();
	while(c>'9'||c<'0') {if(c=='-') f=-1; c=getchar();}
	while(c<='9'&&c>='0') {x=x*10+c-'0'; c=getchar();}
	return f*x; 
}

ymatrix mul ( ymatrix a , ymatrix b )
{
	ymatrix ans ;
	for ( int i = 1 ; i <= n ; ++i )
		for ( int j = 1 ; j <= n ; ++j)
		{
			ans.a[i][j] = 0 ;
			for ( int k = 1 ; k <= n ; ++k )
			{
				ans.a[i][j] += a.a[i][k] * b.a[k][j] ;
				ans.a[i][j] %= p ;
			}
		}
	return ans ;
}

ymatrix quickpow( ymatrix a , ll b )
{
	ymatrix ans , base = a ;
	for ( int i = 1 ; i <= n ; ++i )
		for ( int j = 1 ; j <= n ; ++j )
			ans.a[i][j] = 0 ;
	for ( int i = 1 ; i <= n ; ++i ) ans.a[i][i] = 1 ;
	while ( b )
	{
		if ( b & 1 ) ans = mul ( ans , base ) ;
		base = mul ( base , base ) ;
		b >>= 1 ; 
	}
	return ans ;
}

int main()
{
	scanf("%d",&n) ; k = read() ;
	for ( int i = 1 ; i <= n ; ++i )
		for ( int j = 1 ; j <= n ; ++j )
			A.a[i][j] = read() ;
	ymatrix ans = quickpow(A,k) ;
	for ( int i = 1 ; i <= n ; ++i )
	{
		for ( int j = 1 ; j <= n ; ++j )
			printf("%lld ",ans.a[i][j]) ;
		printf("\n") ;
	}
	return 0 ;
} 

P1962 斐波那契数列

题目链接

P1962 斐波那契数列

代码
#include <iostream>
#include <cstdio>
#define ll long long
using namespace std;

const int maxn=5,p=1e9+7 ;
ll n;
struct ymatrix
{
	ll a[maxn][maxn] ;
}A ;

inline ll read()
{
	ll x=0,f=1;char c=getchar();
	while(c>'9'||c<'0') {if(c=='-') f=-1; c=getchar();}
	while(c<='9'&&c>='0') {x=x*10+c-'0'; c=getchar();}
	return f*x; 
}

ymatrix mul ( ymatrix a , ymatrix b )
{
	ymatrix ans ;
	for ( int i = 1 ; i <= 2 ; ++i )
		for ( int j = 1 ; j <= 2 ; ++j)
		{
			ans.a[i][j] = 0 ;
			for ( int k = 1 ; k <= 2 ; ++k )
			{
				ans.a[i][j] += a.a[i][k] * b.a[k][j] ;
				ans.a[i][j] %= p ;
			}
		}
	return ans ;
}

ymatrix quickpow( ymatrix a , ll b )
{
	ymatrix ans , base = a ;
	for ( int i = 1 ; i <= 2 ; ++i )
		for ( int j = 1 ; j <= 2 ; ++j )
			ans.a[i][j] = 0 ;
	for ( int i = 1 ; i <= 2 ; ++i ) ans.a[i][i] = 1 ;
	while ( b )
	{
		if ( b & 1 ) ans = mul ( ans , base ) ;
		base = mul ( base , base ) ;
		b >>= 1 ; 
	}
	return ans ;
}

int main()
{
	n = read() ;
	if( n == 1 || n == 2 ) printf("1\n") ;
	else
	{
		A.a[1][1] = A.a[1][2] = A.a[2][1] = 1 ;
		A.a[2][2] = 0 ;
		ymatrix ans = quickpow( A , n-2 ) ;
		printf("%lld\n",(ans.a[1][1] + ans.a[1][2]) % p) ;
	}
	return 0 ;
} 

总结与反思

  1. 计算中要注意是否超出数据结构,最好使用 l o n g   l o n g long \ long long long
  2. 掌握构造矩阵的方法,刚接触时难免不熟悉,多推一推就能较好掌握了
  3. 注意全局变量是否与函数内变量冲突
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值