矩阵快速幂的一些题目

这篇博客介绍了如何利用矩阵快速幂算法高效地计算斐波那契数列的第n项。通过展示不同矩阵乘法和快速幂的实现,文章深入探讨了这种算法在处理递归序列问题时的优势,并提供了具体的C++代码实例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

P3390 【模板】矩阵快速幂

a乘上a的n-1次

#include <bits/stdc++.h>
using namespace std;
int n, mod=1000000007; 
long long k;
struct matrix
{
	long long a[101][101];
	//构造函数,将矩阵初始化为0 
	matrix(){
		memset(a, 0, sizeof(a));
	}
	//重载 乘法 运算符,b作为第二个参数 
	matrix operator*(const matrix &b){
		matrix result;
		for(int i=1; i<=n; ++i){
			for(int j=1; j<=n; ++j){
				for(int k=1; k<=n; ++k){
					result.a[i][j]=(result.a[i][j]+a[i][k]*b.a[k][j])%mod;
				}
			}
		}
		return result;
	}
}ans, base;
//矩阵快速幂 
void quickpow(long long asd)
{
	while(asd){
		if(asd&1){
			ans=ans*base;	//用的是重载运算符,不能写成 ans*=base; 
		}
		asd>>=1;
		base=base*base;
	}
}
int main()
{
	scanf("%d %lld", &n, &k);
	for(int i=1; i<=n; ++i){
		for(int j=1; j<=n; ++j){
			scanf("%lld", &base.a[i][j]);
			ans.a[i][j]=base.a[i][j]; 
		}
	}
//	for(int i=1; i<=n; ++i){
//		ans.a[i][i]=1;
//	}
	quickpow(k-1);
	for(int i=1; i<=n; ++i){
		for(int j=1; j<=n; ++j){
			printf("%lld ", ans.a[i][j]);
		}
		printf("\n");
	}
	return 0;
}

单位矩阵* a的n次

#include <bits/stdc++.h>
using namespace std;
int n, mod=1000000007; 
long long k;
struct matrix
{
	long long a[101][101];
	//构造函数,将矩阵初始化为0 
	matrix(){
		memset(a, 0, sizeof(a));
	}
	//重载 乘法 运算符,b作为第二个参数 
	matrix operator*(const matrix &b){
		matrix result;
		for(int i=1; i<=n; ++i){
			for(int j=1; j<=n; ++j){
				for(int k=1; k<=n; ++k){
					result.a[i][j]=(result.a[i][j]+a[i][k]*b.a[k][j])%mod;
				}
			}
		}
		return result;
	}
}ans, base;
//矩阵快速幂 
void quickpow(long long asd)
{
	while(asd){
		if(asd&1){
			ans=ans*base;	//用的是重载运算符,不能写成 ans*=base; 
		}
		asd>>=1;
		base=base*base;
	}
}
int main()
{
	scanf("%d %lld", &n, &k);
	for(int i=1; i<=n; ++i){
		for(int j=1; j<=n; ++j){
			scanf("%lld", &base.a[i][j]);
//			ans.a[i][j]=base.a[i][j]; 
		}
	}
	//单位矩阵 
	for(int i=1; i<=n; ++i){
		ans.a[i][i]=1;
	}
//	quickpow(k-1);
	quickpow(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 斐波那契数列 (矩阵快速幂)

矩阵快速幂求斐波那契数列第n项,递推公式

\\F_n=1*F_{n-1}+1*F_{n-2}\\F_{n-1}=1*F_{n-1}+0*F_{n-2}

\begin{bmatrix} F_n\\ F_{n-1} \end{bmatrix} = \begin{bmatrix} 1 & 1\\ 1 & 0 \end{bmatrix}\begin{bmatrix} F_{n-1}\\ F_{n-2} \end{bmatrix}

进而转换为矩阵幂次

\\F_1=1\\F_2=1

\begin{bmatrix} F_n \\F_{n-1}\end{bmatrix}=\begin{bmatrix} 1 & 1\\ 1 & 0 \end{bmatrix}^{n-2}\begin{bmatrix} F_2\\ F_1 \end{bmatrix}

矩阵快速幂代码

//矩阵快速幂计算  a^n 
#include <bits/stdc++.h>
using namespace std;
int mod=1e9+7;	//模数 
long long n;	 
struct matrix	//定义结构体来表示矩阵 
{
	long long m[3][3];
};
matrix a, an, fib;	//fib是最终斐波那契矩阵, a是矩阵, an为计算完a^n的矩阵
//计算矩阵x(row*column)乘以矩阵y(column*column1),返回值为matrix类型 
matrix mul(matrix x, matrix y, int row, int column, int column1)
{
	//定义一个新矩阵,来保存乘积,记得初始化 
	matrix z;
	for(int i=0; i<3; ++i){
		for(int j=0; j<3; ++j){
			z.m[i][j]=0;
		}
	}	
	//计算乘积,不断取模 
	for(int i=1; i<=row; ++i){
		for(int j=1; j<=column1; ++j){
			for(int k=1; k<=column; ++k){
				z.m[i][j]=(z.m[i][j]%mod+(x.m[i][k]%mod)*(y.m[k][j]%mod))%mod;
			}
		} 
	}
	return z;
}
//矩阵快速幂,计算矩阵asd(row*row)的b次方 
matrix quickpow(matrix asd, long long b, int row)
{
	//定义并初始化单位矩阵、基数矩阵 
	matrix ans, base;
	for(int i=0; i<3; ++i){
		for(int j=0; j<3; ++j){
			ans.m[i][j]=0;
			base.m[i][j]=a.m[i][j];
		}
	}	
	ans.m[1][1]=ans.m[2][2]=1;
	//矩阵快速幂,相当于对b进行二进制拆分 
	while(b){
		if(b&1){
			//ans=ans*base; 
			ans=mul(ans, base, 2, 2, 2);
		}
		b>>=1;
		//base*=base; 
		base=mul(base, base, 2, 2, 2);
	}
	return ans;
}
int main()
{
	scanf("%lld", &n);
	if(n<=2){
		printf("1");
		return 0;
	}
	//初始化a矩阵 
	a.m[1][1]=a.m[1][2]=a.m[2][1]=1;
	//初始化fib矩阵 
	fib.m[1][1]=1;
	fib.m[2][1]=1;
	//计算矩阵a的n-2方 
	an=quickpow(a, n-2, 2);
	//计算最终的斐波那契矩阵 
	fib=mul(an, fib, 2, 2, 1);
	printf("%lld", fib.m[1][1]);
	return 0;
}

双倍经验

P1349 广义斐波那契数列

#include <bits/stdc++.h>
using namespace std;
long long p, q, a1, a2, n, m;
long long f[3][2], base[3][3], temp[3][3];
/*
 p q    fn-1    fn        
 1 0    fn-2    fn-1
 */
 //计算f=base*f矩阵 
 void mul()
 {
 	for(int i=1; i<=2; ++i){
 		for(int j=1; j<=1; ++j){
 			long long sum=0;
 			for(int k=1; k<=2; ++k){
 				sum+=(base[i][k]%m)*(f[k][j]%m);
 				sum%=m;
			 }
			 temp[i][j]=sum;
		 }
	 }
	 for(int i=1; i<=2; ++i){
	 	for(int j=1; j<=1; ++j){
	 		f[i][j]=temp[i][j];
		 }
	 }
 }
 //计算base=base*base 
 void mul2()
 {
 	for(int i=1; i<=2; ++i){
 		for(int j=1; j<=2; ++j){
 			long long sum=0;
 			for(int k=1; k<=2; ++k){
 				sum+=(base[i][k]%m)*(base[k][j]%m);
 				sum%=m;
			 }
			 temp[i][j]=sum;
		 }
	 }
	 for(int i=1; i<=2; ++i){
	 	for(int j=1; j<=2; ++j){
	 		base[i][j]=temp[i][j];
		 }
	 }
 }
int main()
{
	scanf("%lld %lld %lld %lld %lld %lld", &p, &q, &a1, &a2, &n, &m);
	if(n==1){
		printf("%lld", a1);
		return 0;
	} 
	if(n==2){
		printf("%lld", a2);
		return 0;
	}
	f[1][1]=a2;
	f[2][1]=a1;
	//矩阵乘1次能得到f3, 矩阵乘n-2次能得到fn
	base[1][1]=p;
	base[1][2]=q;
	base[2][1]=1;
	n-=2;
	while(n){
		if(n&1){
			//计算f=base*f矩阵 
			mul();
		}
		//计算base=base*base 
		mul2();
		n>>=1;	//n右移一位 
	} 
	printf("%lld", f[1][1]%m);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ypeijasd

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值