題意:
中文題。。。。
解題思路:
fibonacci 模 p 的最小週期.
假設NP(m)表示m的最小週期,滿足:
NP(ab) = lcm(NP(a),NP(b)); 當且僅當(a,b)= 1;
NP(p^d) = NP(p)*p^(d-1);當且僅當p爲素數
如果p爲素數,則
(p%10==2) 週期爲NP(p) = 3
(p%10==5) 週期爲NP(p) = 20
(p%10==1||p%10==9) NP(p) | p-1
(爲p-1的構成周期最小因子)
(p%10==3||p%10==7) NP(p) | 2*p+2
(爲2*p+2的構成周期最小因子)
根據上述公式,可求關於mod p的最小週期爲H,然後求關於mod H的最小週期爲S
原式子 F[F[F[N]]]%P 化爲 F[F[F[N]%S]%H]%P;
再利用矩陣即可求
注意:
要用llu 才能過,lld 可能會wa
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
typedef unsigned long long LL;
#define MAXSZ 50000
#define MAXN 2000000000
void dfs(int ind,LL pro,int cn,LL &ans,bool &flag,LL mod);
LL P;
bool vis[MAXSZ]={};
int p[5000],cnt;
LL fac[5000];
LL A[2][2],E[2][2];
void getpri(){
int n = (int)sqrt(MAXN+0.5);
cnt = 0;
for(int i=2;i<=n;++i){
if(vis[i])continue;
p[cnt++] = i;
for(int j=2*i;j<=n;j+=i){
vis[j] = true;
}
}
}
//void init(){
// A[0][0] = A[0][1]=A[1][0] = 1;
// A[1][1] = 0;
// E[0][0] = E[1][1] = 1;
// E[0][1] = E[1][0] = 0;
//}
LL gcd(LL a,LL b){
if(!b)return a;
return gcd(b,a%b);
}
void quick_mod(LL m,LL mod){
A[0][0] = 1;//A[0][1]=A[1][0] = 1;
A[1][1] = 1;
A[1][0] = A[0][1] = 0;
E[0][0] =1; E[1][1] = 0;
E[0][1] = E[1][0] = 1;
if(m<=0)return;
LL tmp1,tmp2,tmp3,tmp4;
while(m){
if(m&1){
tmp1 = (A[0][0]*E[0][0]+E[1][0]*A[0][1])%mod;
tmp2 = (A[0][0]*E[0][1]+A[0][1]*E[1][1])%mod;
tmp3 = (A[1][0]*E[0][0]+A[1][1]*E[1][0])%mod;
tmp4 = (A[1][0]*E[0][1]+A[1][1]*E[1][1])%mod;
A[0][0] = tmp1; //A[0][0];
A[0][1] = tmp2;//A[0][1];
A[1][0] = tmp3;
A[1][1] = tmp4;
}
m>>=1;
if(!m)break;
tmp1 = (E[0][0]*E[0][0]+E[1][0]*E[0][1])%mod;
tmp2 = (E[0][0]*E[0][1]+E[0][1]*E[1][1])%mod;
tmp3 = (E[1][0]*E[0][0]+E[1][1]*E[1][0])%mod;
tmp4 = (E[1][0]*E[0][1]+E[1][1]*E[1][1])%mod;
E[0][0] = tmp1;
E[0][1] = tmp2;
E[1][0] = tmp3;
E[1][1] = tmp4;
//m>>=1;
}
}
bool isok(LL m,LL mod){
quick_mod(m,mod);
if((A[0][0]+A[0][1])%mod==(1%mod)&&(A[1][0]+A[1][1])%mod==(1%mod)){
return true;
}
return false;
}
void dfs(int ind,LL pro,int cn,LL &ans,bool &flag,LL mod){
if(flag){
if(pro>ans)
return ;
}
if(ind==cn){
if(isok(pro,mod)){
if(flag){
if(ans>pro)ans = pro;
}
else {
flag = true;
ans = pro;
}
}
return;
}
dfs(ind+1,pro,cn,ans,flag,mod);
dfs(ind+1,pro*fac[ind],cn,ans,flag,mod);
}
LL getfac(LL num,LL mod){
int cn = 0;
for(int i=0;i<cnt;++i){
if(num<p[i])break;
while(num%p[i]==0){
num/=p[i];
fac[cn++] = p[i];
}
}
if(num!=1){
fac[cn++] = num;
}
LL ans=0;
bool flag = false;
//dfs(0,1,cn,ans,false,mod);
dfs(0,1,cn,ans,flag,mod);
return ans;
}
LL getNP(LL N){
int tmp = N%10;
if(tmp==2){
return 3;
}
if(tmp==5){
return 20;
}
if(tmp==1||tmp==9){
return getfac(N-1,N);
}
if(tmp==3||tmp==7){
return getfac(2*N+2,N);
}
return 1;
}
LL getT(LL num){
if(num==1){
return 1;
}
LL pw = 1,pd;
LL ans = 1;
LL g;
for(int i=0;i<cnt;++i){
if(num<p[i])break;
if(num%p[i]==0){
pw =1;
while(num%p[i]==0){
num/=p[i];
pw*=p[i];
}
pw/=p[i];
pd = getNP(p[i])*pw;
g = gcd(ans,pd);
ans = (ans/g)*pd;
}
}
if(num!=1){
pd = getNP(num);
g = gcd(ans,pd);
ans = (ans/g)*pd;
}
return ans;
}
int main(){
int T;
getpri();
// int cas = 0;
LL N;
// LL up = 10000;
// for(LL i = 1000000000;i>=2;--i){
// LL T1,T2;
// T1 = getT(i);
// LL tmp0=1,tmp1=1,tmp2;
// LL c=1;
// LL K =i;
// while(1){
// tmp2 = tmp1;
// tmp1 = (tmp0 + tmp1)%K;
// c++;
// tmp0 = tmp2%K;
// if(tmp0==1&&tmp1==1){
// T2 = c-1;
//// printf("%lld\n",c-1);
// break;
// }
// }
// printf("Case: %lld\n",i);
// if(T1!=T2){
// printf("%lld\n",i);
// break;
// }
// }
// printf("YES\n");
scanf("%d",&T);
while(T--){
// init();
scanf("%llu%llu",&N,&P);
LL S =getT(P);
LL H = getT(S);
//LL F = getT(H);
quick_mod(N, H);
LL ans1 = (A[1][1]+A[1][0])%H;
quick_mod(ans1, S);
LL ans2 = (A[1][1]+A[1][0])%S;
quick_mod(ans2, P);
LL ans3 = (A[1][1]+A[1][0])%P;
//printf("Case #%d: %lld\n",++cas,ans);
printf("%llu\n",ans3);
}
return 0;
}