洛谷P1939 【模板】矩阵加速(数列)

本文介绍了使用矩阵加速的方法来解决类似于斐波那契数列的递推问题。通过推导矩阵公式并应用矩阵快速幂,成功实现了高效求解。同时,文章提及了基础矩阵E在矩阵运算中的作用,将其类比于实数中的1。

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

因为对矩阵加速非常不熟悉,所以菜鸡试着做了一下这道题

发现递推式和斐波拉契数列的递推式很像,也就是说应该可以用同样的手法做出来。

那就开始推式子吧:

[axax−1ax−2]=[ax−1+ax−3ax−1ax−2]=[ax−1ax−2ax−3]×[110001100]=⋯=[a3a2a1]×[110001100]x−3=[111]×[110001100]x−3\begin{aligned} \begin{matrix}[a_x&a_{x-1}&a_{x-2}]\end{matrix} &= \begin{bmatrix} a_{x-1}+a_{x-3} & a_{x-1} &a_{x-2} \end{bmatrix} \\ &= \begin{bmatrix} a_{x-1} & a_{x-2} & a_{x-3}\end{bmatrix} \times\begin{bmatrix} 1 & 1 & 0 \\ 0 & 0 &1 \\ 1 & 0 & 0 \end{bmatrix} \\ &= \cdots \\ &= \begin{bmatrix} a_3 & a_2 & a_1\end{bmatrix} \times \begin{bmatrix} 1 & 1 & 0 \\ 0 & 0 &1 \\ 1 & 0 & 0 \end{bmatrix}^{x-3} \\ &= \begin{bmatrix} 1 & 1 & 1 \end{bmatrix} \times \begin{bmatrix} 1 & 1 & 0 \\ 0 & 0 & 1 \\ 1 & 0 & 0 \end{bmatrix}^{x-3} \end{aligned}[axax1ax2]=[ax1+ax3ax1ax2]=[ax1ax2ax3]×101100010==[a3a2a1]×101100010x3=[111]×101100010x3

式子推出来,题目就好办了,矩阵快速幂乱搞一下就AC了

代码:

2019/9/28\rm 2019/9/282019/9/28 重写了一份代码,比之前的那份不知道高到哪里去了好多了。

#include<cstdio>
#include<cstring>
#define rep(i,l,r) for (int i=l; i<=r; ++i)
const int P=1e9+7; int A[3][3];
struct node { int c[3][3]; };
const node F={ { {1,1,0},{0,0,1},{1,0,0} } }; //递推矩阵
const node E={ { {1,0,0},{0,1,0},{0,0,1} } }; //单位矩阵E

void operator *= (node &a,node b) { //这样重载常数要小一点
	node t=a; memset(a.c,0,sizeof a.c);
	rep(i,0,2) rep(j,0,2) rep(k,0,2)
		(a.c[i][j]+=1ll*t.c[i][k]*b.c[k][j]%P)%=P;
}
node _power(node x,int y) { //快速幂
	node ans=E;
	while (y) {
		if (y&1) ans*=x;
		x*=x; y>>=1;
	}
	return ans;
}
	
int main() {
	int T,n; scanf("%d",&T);
	while (T--) {
		scanf("%d",&n); if (n<4) { puts("1"); continue; }
		memcpy(A,_power(F,n-3).c,sizeof A);
		printf("%d\n",(1ll*A[0][0]+A[1][0]+A[2][0])%P);
		//可以手算一下最后一步的矩阵乘法,答案就是这个式子
	}
	return 0;
}

简单地说一下,代码中的 EEE 是一个基础但重要的矩阵,它的左上-右下对角线上的数字是1,其余的都是0。
它的重要特点在于:对于任意的矩阵 AAA ,都有 E×A=AE\times A=AE×A=A。它的意义其实和实数中的1是一样的。
所以在矩阵快速幂函数中,ansansans 初值赋为 EEE 这一步的意义其实相当于普通快速幂中的 ans=1ans=1ans=1

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值