# 矩阵快速幂 计算Fibonacci数列(2020牛客1.J)

J. u's的影响力

题目:

​ 输入(n,x,y,a,b) 。输出 (x^{f(n-2)}*y^{f(n-1)}*a^{[f(n)-1]*b}) .其他f(i)表示Fibonacci数值

题解:

  • 通过观察前几项得到上面的公式。利用矩阵快速幂可以计算很大的Fibonacci数,然后用快速幂求结果。
  • 快速幂中,如果x是模数的倍数,那么对于x=0,y=0的情况,qpow(0,0) = 1,但是应该输出0,这一点要特判一下。
  • 根据费马小定理,若 (p) 是正数,则对任意整数 (a) ,有 (a^{p} equiv a (mod p)) 。两边同时除 (a) 得, (a^{p-1} equiv 1 (mod p)) . 所以可以通过对幂取模来实现降幂。

推荐博客:矩阵构造方法

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MA=1e5+5;
const ll mod=1e9+7;
const ll P=1e9+6;

struct mat{
	ll m[3][3];
	mat(){memset(m,0,sizeof(m));}
};

mat mul(mat x,mat y){	//矩阵乘法
	mat res;
	for(int i=0;i<3;++i)
		for(int j=0;j<3;++j)
			for(int k=0;k<3;++k)
				res.m[i][j]=(res.m[i][j]+x.m[i][k]*y.m[k][j])%P;
	return res;
}

mat power(mat A, ll n){	//矩阵快速幂
	mat c=A,res;
	for(int i=0;i<3;++i) res.m[i][i]=1;
	while(n){
		if(n&1) res=mul(res,c);
		c=mul(c,c);
		n>>=1;
	}
	return res;
}

ll qpow(ll x,ll y){	//快速幂
	if(x%mod==0) return 0;
	ll res=1;
	while(y){
		if(y&1) res=(res*x)%mod;
		x=(x*x)%mod;
		y>>=1;
	}
	return res;
}


ll n,x,y,a,b;

int main()
{
	scanf("%lld%lld%lld%lld%lld",&n,&x,&y,&a,&b);
	x%=mod, y%=mod, a%=mod , b%=P;
	if(n == 1) printf("%lld
",x);
	else if(n == 2) printf("%lld
",y);
	else{
		mat A,B,C;			//辅助矩阵
		ll f1,f2,f3;		//辅助变量,存三个Fibonacci值
		A.m[0][0] = 1, A.m[0][1] = 1, A.m[1][0] = 1;
		B.m[0][0] = 0, B.m[1][0] = 1;
		
		
		C=mul(power(A,n-2) , B);	//计算F(n-2)
		f1=C.m[0][0] ;
		
		C=mul(power(A,n-1) , B);	//计算F(n-1)
		f2=C.m[0][0] ;
		
		C=mul(power(A,n) , B);		//计算F(n);
		f3=b*(C.m[0][0] -1 +P ) %P;

		printf("%lld
",qpow(x,f1)%mod *qpow(y,f2)%mod * qpow(a,f3)%mod);
	}
	return 0;
}

原文地址:https://www.cnblogs.com/A-sc/p/12275039.html