當斐波那契數列%mod時一定存在一個循環節,根據鴿巢原理,mod*(mod-1)一定是一個循環節,但不一定是最短的。
然後求斐波那契數列%n的循環節時,先把n質因數分解,
n=p1a1* p2a2*…*pkak,
然後循環節就是每個pa 的循環節的最小公倍數,pa的循環節即爲num[p]*pow(p,a-1),num[p]是p的循環節。
即爲num[p1] pow(p1,a1-1)與num[p2] pow(p2,a2-1)與…與num[pk] pow(pk,ak-1)的最小公倍數。
num[]求法:只需要求出素數的num即可!
如果數比較小直接暴力即可,因爲最大就是mod * (mod-1),而且實際小很多,個人感覺跑幾千以內素數的num數組暴力是ok的。
如果數大的話,暴力枚舉求出fib[i]%mod==0的最小的i,記爲pos,令a=fib[i-1],然後計算出最小的x使得ax=1(%mod),答案即爲pos * x。
牛客 題中題
這個題打表找到是斐波那契數列,然後因爲需要的num很小,1000以內的質數即可,所以直接暴力的。我以爲得用__int128然而並沒有。
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
long long prime[1010];
int tot;
bool vis[1010];
void init(){
int i,j;
for(i=2;i<=1000;i++){
if(vis[i])
continue;
prime[++tot]=i;
for(j=i+i;j<=1000;j+=i)
vis[j]=true;
}
}
long long num[1010];
int a[501000];
long long gcd(long long a,long long b){
return b?gcd(b,a%b):a;
}
int main(void){
int i;
long long n;
init();
num[1]=3;
for(i=2;i<=tot;i++){
a[1]=1;a[2]=2;
int x=3;
while(1){
a[x]=a[x-1]+a[x-2];
a[x]%=prime[i];
if(a[x]==1&&a[x-1]==0)
break;
x++;
}
num[i]=x;
}
int T;
cin>>T;
while(T--){
scanf("%lld",&n);
long long ans=1;
//cout<<num[1]<<" !!\n";
for(i=1;i<=tot;i++){
//cout<<n<<" "<<prime[i]<<"\n";
if(n%prime[i]==0){
long long x=0;
while(n%prime[i]==0){
n/=prime[i];
x++;
}
long long k=num[i]*pow(prime[i],x-1);
ans=ans/gcd(ans,k)*k;
}
}
printf("%lld\n",ans);
}
return 0;
}