HDU - 5667
题意很简单,给你一个递推式
F1=1
F2=ab
Fn=ab∗Fcn−1∗Fn−2(n>2)
求 F(n)modp
其中 N可以高达 1e18,这赤裸裸地就告诉你解法了,矩阵快速幂搞起
不过这题矩阵需要一点技巧,首先观察可得
Fn
都是 a的幂次
所以我们只需要算指数
Gn
就好了,最后再快速幂算
aGn
然而指数可能比较大,所以我们要用到费马小定理降幂
ap−1≡1(modp)
,其中 p是质数,a要与 p互质
所以 a^(r+k*(p-1))=a^(r) (mod p)
所以对指数
modp−1
就好了
注意点,也是这题坑点,就是要特判一下
amodp=0
的情况
因为使用费马小定理的前提是, a和 p要互质
然后构造矩阵即可
⎡⎣⎢0101c00b1⎤⎦⎥⎡⎣⎢Gn−2Gn−11⎤⎦⎥=⎡⎣⎢Gn−1Gn1⎤⎦⎥
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
#include <set>
#include <queue>
using namespace std;
typedef pair<int,int> Pii;
typedef long long LL;
typedef unsigned long long ULL;
typedef double DBL;
typedef long double LDBL;
#define MST(a,b) memset(a,b,sizeof(a))
#define CLR(a) MST(a,0)
#define Pow2(a) (a*a)
struct Matrix
{
static int MOD;
int siz;
int n[5][5];
Matrix(int tsiz=0):siz(tsiz){CLR(n);}
void E(){CLR(n);for(int i=0; i<siz; i++) n[i][i]=1;}
Matrix operator * (const Matrix &v) const
{
Matrix tem(siz);
for(int i=0; i<siz; i++) for(int j=0; j<siz; j++) for(int k=0; k<siz; k++)
tem.n[i][j]=(tem.n[i][j]+(LL)n[i][k]*v.n[k][j])%MOD;
return tem;
}
};
int Matrix::MOD;
LL N;
int A,B,C,P;
int spPow(int,int,int);
int main()
{
int T;
scanf("%d", &T);
for(int ck=1; ck<=T; ck++)
{
scanf("%lld%d%d%d%d", &N, &A, &B, &C, &P);
if(N==1){puts("1");continue;}
if(N==2){printf("%d\n", spPow(A,B,P));continue;}
if(A%P==0){puts("0");continue;}
N-=2;
Matrix::MOD=P-1;
Matrix ans(3),tem(3);
ans.E();
tem.n[0][0]=0;tem.n[0][1]=1;tem.n[0][2]=0;
tem.n[1][0]=1;tem.n[1][1]=C;tem.n[1][2]=B;
tem.n[2][0]=0;tem.n[2][1]=0;tem.n[2][2]=1;
while(N)
{
if(N&1) ans=ans*tem;
tem=tem*tem;
N>>=1;
}
int tim=((LL)B*ans.n[1][1]+(LL)ans.n[1][2])%(P-1);
printf("%d\n", spPow(A,tim,P));
}
return 0;
}
int spPow(int tem,int tim,int MOD)
{
int res=1;
while(tim)
{
if(tim&1) res=((LL)res*tem)%MOD;
tem=((LL)tem*tem)%MOD;
tim>>=1;
}
return res;
}