UVa11582 巨大的斐波那契数列(循环节问题)

题干:

给你三个数a,b,c,求 F[ a b a^b ]%c的值,F[i]表示第i个斐波那契数。
其中0<a,b< 2 64 2^{64}

思路:

2 64 2^{64} 有20位,需要用unsigned long long来存储,用cin和cout来输出输出。
我们先来写一下斐波那契数列的前十位
1 1 2 3 5 8 13 21 34 55
1 1 0 1 1 0  1   1   0   1(c=2的时候3个一次循环(1 1 0))
1 1 2 0 2 2  1   0   1   1(c=3的时候8个一次循环(1 1 2 0 2 2 1 0))
一个数模n的余数最多有n种,所以最多有 n 2 n^2 项重复出现,所以对F[0]~F[ n 2 n^2 ]进行暴力,找到开始循环的地方,然后记录下来,就可以将 a b a^b 缩小了。
设周期位M,则F[ a b a^b ]%c == F[ x b x^{b} %M] (x=a%M).

#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <math.h>
using namespace std;
typedef unsigned long long ll;
int f[1200][6200],F[6200];
ll qc(ll a,ll b,int c)
{
	ll ans=1;
	while(b)
	{
		if(b&1)
			ans=(ans*a)%c;
		a=(a*a)%c;
		b>>=1;
	}
	return ans%c;
}
int main()
{
	int t,c;
	for(int i=2;i<=1100;i++){
		f[i][0]=f[i][1]=1;
		for(int j=2;;j++){
			f[i][j]=(f[i][j-1]+f[i][j-2])%i;
			if(f[i][j]==1&&f[i][j-1]==1){
				F[i]=j-1;
				break;
			}
		}
	}
	scanf("%d",&t);
	while(t--)
	{
		ll a,b;
		cin>>a>>b>>c;
		if(c==1)
		{
			printf("0\n");
			continue;
		}
		cout<<f[c][qc(a%F[c],b,F[c])-1]<<endl;
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42279796/article/details/88828278