UVA11582- Colossal Fibonacci Numbers! 斐波那契数列循环节问题

该博客探讨了在大整数环境下,如何高效计算斐波那契数列第ab项模n的值。通过分析斐波那契数列的循环节特性,提出利用周期性简化计算的方法。博主首先排除了矩阵快速幂在大数场景下的应用,然后阐述了寻找循环节的原理,并给出具体实现代码。通过寻找斐波那契数列的循环节,将复杂问题转化为简单位置的计算,最终解决了大整数模运算的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目意思很简单,给定a、b、n,求斐波那契数列第ab项模n的值,那么如何考虑呢?

  • 首先我们应该知道求斐波那契数列的任意一项可以使用矩阵快速幂,速度很快,但是对于这道题,由于a和b都非常大,所以不能使用这种方法,考虑到最后都要模一个n,考虑斐波那契数列会出现循环节,如果要问为什么,因为斐波那契数列连续两项和等于后一项,所以如果出现和最开始相同的两项,那么就说明找到了循环的位置,而且这循环节一定存在
  • 为什么?可以这样考虑,根据斐波那契数列的性质,设数列为A,如果能够找到Ai mod n = Ak mod n并且Ai+1 mod n = Ak+1 mod n,那么Ai到Ak-1就是一个循环节,周期为k-i,那么每一个数都模n,相邻两项只有n * (n - 1)种情况,那么根据抽屉原理(鸽巢原理),最多寻找n * (n - 1) + 1项就会找到这个循环节
  • 所以可以看出随着n的不同,斐波那契循环节在发生变化,且对于每一个n应该有唯一一个循环节,也就是说这是一个周期函数的问题,这样我们就可以利用周期将任意一个位置化成一个最简单的位置。这道题的n范围是1000,时间也是可以接受的
#include <iostream>
using namespace std;
typedef unsigned long long ull;
const int MAXN = 1e6 + 100;
ull Data[MAXN];
int fastpow(ull base, ull power, int MOD){
	ull ans = 1;
	while(power){
		if(power & 1) ans = ans * base % MOD;
		base = base * base % MOD;
		power >>= 1;
	}
	return ans % MOD;
}
ull solve(ull a, ull b, int n){
	Data[0] = 0;
	Data[1] = 1;
	int len;
	int MOD = n;
	for(int i=2;1;i++){
		Data[i] = (Data[i - 1] + Data[i - 2]) % MOD;
		if(Data[0] == Data[i - 1] && Data[1] == Data[i]){
			len = i - 1;
			break;
		}
	}
	int pos = fastpow(a % len, b, len);//找位置
	//考虑到a非常大,根据乘法取模的性质,将a取模,否则出错
	return Data[pos];
}
int main(){
	ull a, b;
	int t, n;
	cin >> t;
	while(t--){
		cin >> a >> b >> n;
		if(n == 1) cout << 0 <<"\n";
		//特判的原因是如果n为1,那么就会陷入死循环,因为算出来的Data值都是0
		//最好特判一下,如果不特判也可以处理,将Data[1]取为1%n
		else cout << solve(a, b, n) <<"\n";
	}
	return 0;
}
  • 因为涉及到取模的问题都会出现模完为0的情况,所以设计数组的时候直接设置Data[0],这样方便处理
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Clarence Liu

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

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

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

打赏作者

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

抵扣说明:

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

余额充值