FRS2 - Fibonaccibonacci(easy)

FRS2 - Fibonaccibonacci(简单)

狮子座想玩一些非常大的数字,好吧......

设FIB斐波那契函数:
FIB(0)= 0; FIB(1)= 1 

对于N> = 2 FIB(N)= FIB(N-1)+ FIB(N-2)

实施例:我们有FIB(6)= 8,和FIB(8)= 21,所以FIB(FIB(6))= 21

输入

输入以单行中的测试用例数T开头。
在下一个T行的每一行中,存在整数N.

输出

对于每个测试用例,打印FIB(FIB(N)),
给出你的答案模1000000007。

 

链接原题

https://www.spoj.com/problems/FRS2/

此题的关键就在求f(n)的循环节

 

贴上AC代码,代码中有解释。

#include <iostream>
#include <cstdio>
#include <ctime>
#include <cstring>
#include <cstdlib>
#define p 1000000007
#define mod1 2000000016
#define mod2 329616
#define MAXN 1010
using namespace std;

//定义结构体,就是矩阵
struct node{
	long long j[2][2];
}k,temp;


//读入,并且对329616求余
long long read(){
	char s[MAXN];
	scanf("%s",s);
	long long tmp=0;
	for(int i=0;i<strlen(s);++i){
		tmp=(tmp*10+s[i]-'0')%mod2;
	} 
	return tmp;
}


//重载运算符,矩阵相乘
node operator *(node x1,node y1){
	node lx;
	for(int i=0;i<2;++i){
		for(int j=0;j<2;++j){
			lx.j[i][j]=0;
		}
	}
	for(int i=0;i<2;++i){
		for(int j=0;j<2;++j){
			for(int ll=0;ll<2;++ll){
				lx.j[i][j]=(lx.j[i][j]+(x1.j[i][ll]*y1.j[ll][j])%mod1)%mod1;
			}
		}
	}
	return lx;
}


//再次重载。。。。。。
//发现前后两次求余的数不同,有重载了一次
//不想再写个函数了,就直接抄了一下
node operator -(node x1,node y1){
	node lx;
	for(int i=0;i<2;++i){
		for(int j=0;j<2;++j){
			lx.j[i][j]=0;
		}
	}
	for(int i=0;i<2;++i){
		for(int j=0;j<2;++j){
			for(int ll=0;ll<2;++ll){
				lx.j[i][j]=(lx.j[i][j]+(x1.j[i][ll]*y1.j[ll][j])%p)%p;
			}
		}
	}
	return lx;
}

int main(){
	//freopen("Fibonaccibonacci.in","r",stdin);
	//freopen("Fibonaccibonacci.out","w",stdout);

    //此处是测试用的,为了求出f(n)(就是斐波那契数列)对p求余的循环节mod1
    //然后再次求出对mod1求余的循环节mod2,简化运算
    //最后的答案就是f[f[n % mod2] % mod1] % p
	/*long long a,b,time1=0;
	a=0,b=1;
	while(1){
		++time1;
		long long tmp=(a+b)%mod1;
		a=b;
		b=tmp;
		if(a==0&&b==1){
			printf("%d",time1);
			break;
		}
	}*/
	long long n,T;
	scanf("%lld",&T);
	for(int ba=1;ba<=T;++ba){
		long long x=read();
		k.j[0][0]=1;k.j[0][1]=1;
		k.j[1][0]=1;k.j[1][1]=0;
		temp.j[0][0]=1;temp.j[0][1]=0;
		temp.j[1][0]=0;temp.j[1][1]=1;
        //第一次快速幂,求f[n % mod2] % mod1的值
		while(x){
			if(x%2){
				temp=temp*k;
			}
			k=k*k;
			x/=2;
		}
		long long re=temp.j[0][1];
		k.j[0][0]=1;k.j[0][1]=1;
		k.j[1][0]=1;k.j[1][1]=0;
		temp.j[0][0]=1;temp.j[0][1]=0;
		temp.j[1][0]=0;temp.j[1][1]=1;
        //第二次快速幂,求f[f[n % mod2] % mod1] % p的值,也就是答案
		while(re){
			if(re%2){
				temp=temp-k;
			}
			k=k-k;
			re/=2;
		}
		printf("%lld\n",temp.j[0][1]);
	}
	return 0;
}

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值