矩阵加速递推式递推

前提

矩阵乘法板子

struct martix{
	ll m[10][10];
	void init(){clean(m,0);}
};
inline martix mutiply(martix input1,martix input2,int a,int b,int c){
	martix output;
	output.init();
	loop(i,1,a){
		loop(j,1,b){
			loop(k,1,c){
				output.m[i][k]+=input1.m[i][j]*input2.m[j][k];
				output.m[i][k]%=mod;
			}
		}
	}
	return output;
}

快速幂板子

inline martix fastpower(martix a,int times){
	martix stag=a;
	martix res=start_;//start_是单位矩阵,可以通过构造构造出此矩阵为对角线为1,其他都为0的矩阵
	while(times){
		if(times&1)res=mutiply(res,stag,2,2,2);
		times>>=1;
		stag=mutiply(stag,stag,2,2,2);
	}
	return res;
}

fibonacci 第n项

转化过程

  • StepOne:写出递推式: f [ i ] = f [ i − 1 ] + f [ i − 2 ] f[i]=f[i-1]+f[i-2] f[i]=f[i1]+f[i2]
  • StepTwo:考虑矩阵

首先, f [ i ] f[i] f[i]是由 f [ i − 1 ] , f [ i − 2 ] f[i-1],f[i-2] f[i1],f[i2]得出来的,所以当前矩阵应该需要 f [ i ] , f [ i − 1 ] , f [ i − 2 ] f[i],f[i-1],f[i-2] f[i],f[i1],f[i2]

然后根据所有的已知条件写出如下草稿:

在这里插入图片描述

问号那一团就是我们要构造的转移矩阵

根据等量关系:

f [ n ] = f [ n − 1 ] + f [ n − 2 ] f[n]=f[n-1]+f[n-2]\\ f[n]=f[n1]+f[n2]

左边那一竖列问号应该是1

根据等量关系:

f [ n − 1 ] = f [ n − 1 ] + 0 × f [ n − 2 ] f [ n − 2 ] = f [ n − 2 ] + 0 × f [ n − 1 ] f[n-1]=f[n-1]+0\times f[n-2]\\ f[n-2]=f[n-2]+0\times f[n-1] f[n1]=f[n1]+0×f[n2]f[n2]=f[n2]+0×f[n1]

右面一竖列问号号应该是1和0

最后构造出来的矩阵是:

在这里插入图片描述

设构造出的转移矩阵为s,初始答案矩阵为a,斐波那契数列的第n项为x,则

a = ( f [ 3 ] f [ 2 ] f [ 2 ] f [ 1 ] ) s = ( 1 1 1 0 ) 令 矩 阵 k = a × s n − 3 x = k 1   1 a=\begin{pmatrix} f[3] & f[2]\\ f[2] &f[1]\\ \end{pmatrix} \\s= \begin{pmatrix} 1&1\\1&0 \end{pmatrix} \\令矩阵k=a\times s^{n-3} \\x=k_{1\ 1} a=(f[3]f[2]f[2]f[1])s=(1110)k=a×sn3x=k1 1

  • StepThree:可以搞了:
#include<bits/stdc++.h>
using namespace std;
#define loop(i,start,end) for(register int i=start;i<=end;++i)
#define clean(arry,num) memset(arry,num,sizeof(arry))
#define anti_loop(i,start,end) for(register int i=start;i>=end;--i)
#define ll long long
template<typename T>void read(T &x){
	x=0;char r=getchar();T neg=1;
	while(r>'9'||r<'0'){if(r=='-')neg=-1;r=getchar();}
	while(r>='0'&&r<='9'){x=(x<<1)+(x<<3)+r-'0';r=getchar();}
	x*=neg;
}
ll n,mod;
const int maxn=2e9+10;
const int maxm=1e9+10+10;
struct martix{
	ll m[10][10];
	void init(){clean(m,0);}
}start_;
inline martix mutiply(martix input1,martix input2,int a,int b,int c){
	martix output;
	output.init();
	loop(i,1,a){
		loop(j,1,b){
			loop(k,1,c){
				output.m[i][k]+=input1.m[i][j]*input2.m[j][k];
				output.m[i][k]%=mod;
			}
		}
	}
	return output;
}
inline martix fastpower(martix a,int times){
	martix stag=a;
	martix res=start_;
	while(times){
		if(times&1)res=mutiply(res,stag,2,2,2);
		times>>=1;
		stag=mutiply(stag,stag,2,2,2);
	}
	return res;
}
int main(){
	#ifndef ONLINE_JUDGE
	//freopen("datain.txt","r",stdin);
	#endif
	read(n);
	read(mod);
	start_.init();
	start_.m[1][1]=start_.m[2][2]=1;
	martix ans;
	ans.init();
	ans.m[1][1]=2;ans.m[1][2]=1;ans.m[2][1]=1;ans.m[2][2]=1;
	if(n<=3){
		if(n==3)printf("2\n");
		else printf("1\n");
	}
	else{
		martix zhuanzhi;zhuanzhi.init();
		zhuanzhi.m[1][1]=1;zhuanzhi.m[1][2]=1;zhuanzhi.m[2][1]=1;zhuanzhi.m[2][2]=0;
		ans=mutiply(ans,fastpower(zhuanzhi,n-3),2,2,2);
		printf("%lld\n",ans.m[1][1]);
	}
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

AndrewMe8211

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

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

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

打赏作者

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

抵扣说明:

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

余额充值