SP12007 FRS2 - Fibonaccibonacci (easy) 题解

题目传送门 洛谷题目传送门

思路

众所周知,斐波那契数列在模意义下是有周期的,我们设在模 1 0 9 + 7 10^9+7 109+7 的时候的周期是 T 1 T1 T1,在模 T 1 T1 T1 的时候的周期是 T 2 T2 T2,那么式子就变成了: F ( F ( n   m o d   T 2 )   m o d   T 1 ) F(F(n\bmod T2)\bmod T1) F(F(nmodT2)modT1)

这个式子是可以用矩乘的,不会矩乘求斐波那契的出门左转

如何求 T 1 , T 2 T1,T2 T1,T2 呢?暴力!直接上线性递推式求周期!

#include <bits/stdc++.h>
#define int long long
int a,b,ans,mod,tmp;
signed main()
{
	cin>>mod;
	a = 1,b = 1;
	do
		ans++,tmp = b,b = (a+b)%mod,a = tmp;
	while(a!=1||b!=1);
	cout<<ans;
	return 0;
}

为什么我写暴力,因为我不会其他的!

你还别说跑得还挺快。

得到 T 1 = 2000000016 , T 2 = 329616 T1=2000000016,T2=329616 T1=2000000016,T2=329616

用矩乘求就行了。

代码

#include <bits/stdc++.h>
#define int long long
using namespace std;

template<typename T> void read(T &x)
{
	x = 0;
	T f = 1;char ch = getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-')
		{
			f = -1,ch = getchar();
			break;
		}
		ch = getchar();
	}
	while(ch>='0'&&ch<='9')
		x = ((x<<3)+(x<<1)+ch-48)%329616,ch = getchar();//边快读边取模
	x*=f;
}
template<typename T> T read()
{
	T x;read(x);return x;
}
template<typename T> void write(T x)
{
    if(x<0) x = -x,putchar('-');
    if(x<=9) return putchar(x+48),void();
    write(x/10);
    putchar(x%10+48);
}
template<typename T> void writen(T x)
{
    write(x);
    puts("");
}
struct node{
	int c[5][5];
	void clear(int x)
	{
		for(int i = 0;i<5;i++)
			for(int j = 0;j<5;j++)
				c[i][j] = x;
	}
}a;
node mul(node x,node y,int mod)
{
	node res;
	res.clear(0);
	for(int i = 1;i<=2;i++)
		for(int j = 1;j<=2;j++)
			for(int k = 1;k<=2;k++)
				(res.c[i][j]+=x.c[i][k]*y.c[k][j])%=mod;
	return res;
}
int qpow(int y,int mod)
{
	node res,x;
	x.clear(0);
	x.c[1][1] = x.c[1][2] = x.c[2][1] = 1;
	res.clear(0);
	res.c[1][1] = res.c[1][2] = 1;
	if(y==0) return 0;
	if(y<2) return 1;
	y-=2;
	while(y)
	{
		if(y&1) res = mul(res,x,mod);
		y>>=1;
		x = mul(x,x,mod);
	}
	return res.c[1][1];
}
int n;
void solve()
{
	read(n);
	int m = qpow(n,2000000016ll);
	writen(qpow(m,1000000007ll));
}
signed main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	int T;
	read(T);
	while(T--) solve();
	return 0;
}
  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值