斐波那契矩阵幂以及费马小定理求余应用

最近遇到费马小定理的一道应用题,思考了几个小时,理清了思路,终于证明了费马小定理求指数余以及矩阵幂求斐波那契结论;

先入为主(偷懒=_=),上题;

不一样的斐波那契数列(二)

Description

自从荟荟上了奥术课之后,她就觉得自己十分强大,但是万恶的数学老师说我们现在来讨论一下斐波那契数列。荟荟说,我知道。老师说,你知道很好,那么我们今天我们变形一下。

已知

F(0)=a

F(1)=b

F(n)=F(n-1)*F(n-2) (n>=2)

求F(n)

答案mod 1000000007 (1e9+7)


Input

多组数据输入,每组数据第一行输入三个整数a,b,n。

0<=a,b,n<=1e16


Output

对于每组数据输出F(n) mod 1000000007 (1e9+7)

#include<iostream>
#include<stdio.h>
// a ,b , ab ,a^1b^2 ,a^2b^3 
//可以发现 数列F(N)的指数存在斐波那契的变化趋势,
//那么直接根据对应关系求出f(N)的 指数,最后用快速幂即可;
// 其中 矩阵求求斐波那契以及费马小定理的求余较难,但仔细想想就可以理解;
// 1.斐波那契数列 :1,1,2,3,5,8…… 
//		可以由矩阵求的;
//		构造矩阵A  1 0    系数矩阵B  1  1      
// 				  0 1			   1  0
//C(0)=A*B^0 = 1 0	C(1) = A*B^1= 1  1 	C(2)=A*B^2=  2  1   …… 
//	      		 0 1		  		  1  0		   		   1  1
//	恰好 有c(N-1).x[1][0]是 F(N)的a的指数,同时C(N-1).x[0][0]是F(N)的b的指数; 
//归纳说明:由此 可根据矩阵幂来求得斐波那契数;
//	2 .  费马小定理 的应用;
//  有公式: a^(p-1)(MOD p)= 1 (p为质数); 结论:(a^(M%(p-1)) )(mod p)=a^m(mod p);
//  证明如下: m=(p-1)*k+l; 
//	a^m(mod p)=( a^(l)*a^(k*(p-1))  )(mod p) 
//= (a^(l)(mod p)*a^(k*(p-1))(mod p) ) (mod p)
//=	a^(l)(mod p)
//=	a^(M%(p-1)(mod p);
// 证毕;
// 也就是说 反正对指数就可以对其MOD(p-1);
// 神奇吧!
//3 还有个小问题:底数可不可以取余呢? 可以!
// 但是要取余P,而不是p-1;
//  道理和乘法求余公式一样的 :(a*b)(mod p)= (a mod  p)*(b mod p )(mod p) ;
 
using namespace std;
typedef long long ll;
const int MOD = 1000000007;
const int MOD2 = 1000000006;
struct matrix{
	ll x[2][2];
	matrix()
	{
		for(int i=0;i<2;i++)
			for(int j=0;j<2;j++)
				x[i][j]=0;
	}
}; 
typedef matrix mat;
mat mul(mat a, mat b){
	mat	tmp;
	for(int i=0;i<2;i++)
		for(int j=0;j<2;j++)
			for(int k=0;k<2;k++)
			//费马小定理对指数的应用; 
				tmp.x[i][j] = (tmp.x[i][j] + (ll)a.x[i][k] * b.x[k][j] % MOD2) % MOD2;  
	return tmp; 
}

mat quickmul(mat a,ll  n)
{
	mat ans;
	for(int i=0;i<2;i++)
			ans.x[i][i] = 1;
	while(n>0)
	{
		if(n&1)
			ans = mul(ans,a);   //矩阵顺序??? 
			n >>= 1;
			a = mul(a,a);		
	}
	return ans;
}
ll quickmi(ll a, ll p)
{
	if(p==0)
		return 1; 
	ll ans=1;
	a = a % MOD;
	p = p % MOD;
	while(p>0)
	{
		if(p&1)
			ans = (ans*a)%MOD;
		a = (a*a)%MOD;
		p >>= 1;
	}
	return ans;
}
void print(mat a)
{
	for(int i=0;i<2;i++)
	{			
		for(int j=0;j<2;j++)
			cout<<a.x[i][j]<<' ';
			cout<<endl;
	}
}
int main(){
	ll a,b,n,ans;
	while(~scanf("%lld%lld%lld", &a,&b,&n))
	{
	
		if(n>0)
		{
			a %= MOD;
			b %= MOD;
			mat f1, fa;
			
			f1.x[0][0]=1;f1.x[1][0]=1;f1.x[0][1]=1;
			fa = quickmul(f1,n-1);
		//	print(fa);
 			ans = ( quickmi(a, fa.x[1][0] ) *  quickmi(b,fa.x[0][0]) )% MOD;
 	//		printf("%lld %lld \n",fa.x[1][0],fa.x[0][0]);
	 //		printf("%lld %lld\n",( quickmi(a, fa.x[1][0] % (MOD-1) ) % MOD ), ( quickmi(b,fa.x[0][0]%(MOD-1)) % MOD ) );
			printf("%lld\n", ans);
		}
		else
		{
			if(n==0)
			printf("%d\n", a);
			else if(n==1)
			printf("%d\n", b);		
		}
	}	
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值