hdu 2814 Interesting Fibonacci

本文提供了一道关于斐波那契数列的数学算法题的解答思路,通过模运算和快速幂操作来降低计算复杂度。

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

##题目链接
http://acm.hdu.edu.cn/showproblem.php?pid=2814
##题意
给出a,b,n,c,求 F ( a b ) F ( a b ) n − 1 % c F(a^{b})^{F(a^b)^{n-1}}\%c F(ab)F(ab)n1%c,F(x)表示斐波那契函数。
##思路
先利用 a b % p = a φ ( p ) + b % φ ( p ) a^{b}\%p = a^{\varphi (p) + b\%\varphi (p)} ab%p=aφ(p)+b%φ(p)降幂,再用找斐波那契模一个数有循环节的特点降 a b a^{b} ab,这两个比较大的数降完以后就是无脑快速幂。
下面是推倒过程:
F ( a b ) F ( a b ) n − 1 % c F(a^{b})^{F(a^b)^{n-1}}\%c F(ab)F(ab)n1%c
= ( F ( a b ) % c ) F ( a b ) n − 1 % c =(F(a^{b})\%c)^{F(a^b)^{n-1}}\%c =(F(ab)%c)F(ab)n1%c
我们先处理底 F ( a b ) % c F(a^{b})\%c F(ab)%c
∵ F ( x ) % c 存 在 循 环 节 , 设 m o d 为 循 环 的 周 期 , p o s 为 循 环 的 起 始 位 置 \because F(x)\%c存在循环节,设mod为循环的周期,pos为循环的起始位置 F(x)%c,modpos
∴ F ( a b ) % c = F ( ( a b − p o s ) % m o d + p o s ) % c = F ( a b % m o d + p o s − p o s % m o d ) % c \therefore F(a^b)\%c=F((a^b-pos)\%mod+pos)\%c=F(a^b\%mod+pos-pos\%mod)\%c F(ab)%c=F((abpos)%mod+pos)%c=F(ab%mod+pospos%mod)%c
然后是幂,用上面的公式
原 式 = ( F ( a b ) % c ) ϕ ( c ) + F ( a b ) n − 1 % ϕ ( c ) % c 原式=(F(a^{b})\%c)^{\phi(c)+F(a^b)^{n-1}\%\phi(c)}\%c =(F(ab)%c)ϕ(c)+F(ab)n1%ϕ(c)%c
F ( a b ) n − 1 % ϕ ( c ) = ( F ( a b ) % ϕ ( c ) ) n − 1 % ϕ ( c ) F(a^b)^{n-1}\%\phi(c)=(F(a^b)\%\phi(c))^{n-1}\%\phi(c) F(ab)n1%ϕ(c)=(F(ab)%ϕ(c))n1%ϕ(c)
和上面的处理方法一样
##代码

#include<cstdio>
#include<cstdlib>
#include<map>
#include<set>
#define ULL unsigned long long
#define mp(x,y) make_pair(x,y)
using namespace std;
int phi[310];
int fib1[90010],fib2[90010];
map<pair<int,int>,int> fibb;
int pos[90010];
void init(){
	for(int i=1;i<=300;++i) phi[i]=i;
	for(int i=2;i<=300;i+=2) phi[i]/=2;
	for(int i=3;i<=300;i+=2)
		if(phi[i]==i)
			for(int j=i;j<=300;j+=i)
				phi[j]=phi[j]/i*(i-1);	
}
ULL powMod(ULL a,ULL b,int c){
	ULL ret=1;
	a%=c;
	while(b){
		if(b&1) ret=ret*a%c;
		a=a*a%c;
		b/=2; 	
	}	
	return ret;
}
int main(){
	int t;
	init();
	scanf("%d",&t);
	for(int ca=1;ca<=t;++ca){
		ULL a,b,n,F1,F2;
		int c,mod1,mod2,pos1,pos2;		
		scanf("%I64u%I64u%I64u%d",&a,&b,&n,&c);
		fibb.clear();
		fib1[1]=1%c;
		fib1[2]=1%c;
		fibb.insert(mp(mp(fib1[1],fib1[2]),2));
		for(int i=3;i<=c*c+2;++i){
			fib1[i]=(fib1[i-1]+fib1[i-2])%c;
			if(!fibb.insert(mp(mp(fib1[i-1],fib1[i]),i)).second){
				pos1=fibb[mp(fib1[i-1],fib1[i])];
				mod1=i-pos1;
				break;
			}		
		}
		fibb.clear();
		fib2[1]=1%phi[c];
		fib2[2]=1%phi[c];
		fibb.insert(mp(mp(fib2[1],fib2[2]),2));
		for(int i=3;i<=phi[c]*phi[c]+2;++i){
			fib2[i]=(fib2[i-1]+fib2[i-2])%phi[c];
			if(!fibb.insert(mp(mp(fib2[i-1],fib2[i]),i)).second){
				pos2=fibb[mp(fib2[i-1],fib2[i])];
				mod2=i-pos2;
				break;
			}		
		}
		F2=powMod(fib2[powMod(a,b,mod2)+pos2-pos2%mod2],n-1,phi[c])+phi[c];
		F1=fib1[powMod(a,b,mod1)+pos1-pos1%mod1];
		//printf("%d %d\n",pos2,mod2);
		//printf("%I64u\n",powMod(a,b,mod1)+pos1-pos1%mod1);
		//printf("%I64u %I64u\n",F1,F2);
		printf("Case %d: %I64u\n",ca,powMod(F1,F2,c));
	}	
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值