思路:我们手写几步fn的话,就能看出来,事实上到最终是一堆a^b相乘,所以我们要算的其实就是a的几次方。
1.首先我们要算,a到底要乘多少次
我们假设fn = (ab)p[n]
可得: (ab)p[n]= ab * ((ab)p[n-1])c * ((ab)p[n-2]); n > 2
从上式可得:p[n]=c*p[n-1]+p[n-2]+1;
从上述的递推式,我们就可以来构造矩阵了
p[n] c 1 1 p[n-1]
p[n-1]
= 1 0 0 * p[n-2]
1 0 0 1 1
然后我们可以继续用这样的关系表示乘号右边的矩阵,因此递推到最后就变成了
所以我们只要求得初始系数矩阵的(n-2)次,再做运算,就可以得到pn,最后再乘b就行。
2.其次如果求得的pn特别大怎么办?这时我们需要对pn取模,那怎样取模才不会影响最后的运算呢?这里就需要“费马小定理”。
费马小定理: 假如p是质数,且gcd(a,p)=1,那么(a^(p-1))%p=1
一开始我看了这个定理仍然不知道怎么取模,然后学长跟我提了几句:①a^p = a * a^p-1 ② (a^(p-1)) % p = 1 那么 a^p % p = a % p
直白点的意思就是,对如果a,p互质,那么对a来说,a的几次方再对模p的结果,事实上是一个循环,这个循环的大小就是p-1。
因此我们需要在第一步里,求pn的过程中对p-1取模。
3.此时通过第一二两步已经得到了a最终需要的指数,这就是一个普通的快速幂。
总结:初学矩阵快速幂,对这类型的之前还是处于一知半解状态,我认为关键是熟练从递推式来构造矩阵的过程。
代码:
import java.util.*;
class Matrix{
long [][] m = new long[3][3];
}
public class Main{
static Scanner sc = new Scanner(System.in);
static int t;
static long n,a,b,c,p;
static final int MOD = 10000;
static long p(long x, long k) {
long ans = 1;
while(k > 0) {
if((k&1) == 1)
ans = (ans * x) % p;
x = (x * x) % p;
k >>= 1;
}
return ans;
}
static Matrix multi(Matrix a, Matrix b) {
Matrix tmp = new Matrix();
for(int i = 0; i < 3; i++) {
for(int j = 0; j < 3; j++) {
for(int k = 0; k < 3; k++) {
tmp.m[i][j] += (a.m[i][k] * b.m[k][j]) % (p-1);
}
}
}
return tmp;
}
static long matrix_p(Matrix a, long k) {
Matrix ans = new Matrix();
ans.m[0][0] = 1; ans.m[1][1] = 1; ans.m[2][2] = 1;
while(k > 0) {
if((k&1) == 1)
ans = multi(ans,a);
a = multi(a,a);
k >>= 1;
}
return (ans.m[0][0]*b + ans.m[0][2]*b) % (p-1);
}
public static void main(String[] args) {
t = sc.nextInt();
while(t-- > 0) {
n = sc.nextLong();
a = sc.nextLong(); b = sc.nextLong(); c = sc.nextLong();
p = sc.nextLong();
if(n == 1 || a%p == 1) {//1 or mod == 1
System.out.println(1);
}
else if(n == 2) {//2
if(a%p == 0)//这题还有个坑点,就是如果a%p == 0的话,结果肯定是0
System.out.println(0);
else {
long ans = p(a,b);
System.out.println(ans);
}
}
else { //otherwise
if(a%p == 0)
System.out.println(0);
else {
Matrix x = new Matrix();
x.m[0][0] = c;
x.m[0][1] = 1; x.m[0][2] = 1; x.m[1][0] = 1; x.m[2][2] = 1;
long k = matrix_p(x,n-2);
System.out.println(p(a,k));
}
}
}
}
}