1. 程式人生 > >Sequence 矩陣快速冪 + 費馬小定理

Sequence 矩陣快速冪 + 費馬小定理

f[1] = 1

f[2] = a ^ b

f[n]\quad =\quad { a }^{ b }\quad *\quad { f[n-1] }^{ c }\quad *\quad f[n-2]

其實不是很好的去想到取log的 

兩邊同時取log

\log _{ a }{ f[n]\quad =\quad \log _{ a }{ ({ a }^{ b }\quad *\quad { f[n-1] }^{ c }\quad *\quad f[n-2]) } } \\ \qquad \qquad \quad \quad =\quad b\quad +\quad c\log _{ a }{ f[n-1]\quad + } \log _{ a }{ f[n-1] } \quad \qquad \\ \\ F[n]\quad =\quad \log _{ a }{ f[n] } \qquad \\ F[n]\quad =\quad b\quad +\quad cF[n-1]\quad +\quad F[n-2]\\ F[3]\quad =\quad b\quad +\quad cF[2]\quad +\quad F[1]\\ \begin{pmatrix} F[2] & F[1] & b \end{pmatrix}\begin{pmatrix} c & 1 & 0 \\ 1 & 0 & 0 \\ 1 & 0 & 1 \end{pmatrix}\quad =\quad \begin{pmatrix} F[3] & F[2] & b \end{pmatrix}\\

然後 F[2] = b  F[1] = 0

則 f[n] = a^(F[n]) % p  

費馬小定理 : 

① 判斷素數,對於大素數的判定,Miller-Rabin 素數判定 ②求解逆元 ,設a模p的逆元為x,則a*x≡1(mod p) ,(a,p)=1;由費馬小定理可以知道x=a^(p-2) ③對於計算ab(modp)ab(modp) 可簡化             對於素數p,任取跟他互素的數a,有a^(p-1)(mod p)=1             所以任取b,有a^b%p=a^(b%(p-1))(%p)從而簡化運算。

本文來自 楊美人 的部落格 ,全文地址請點選:https://blog.csdn.net/qq_40679299/article/details/80596406?utm_source=copy

然後 f[n] = a^(F[n] mod (p - 1) ) mod p

程式碼:

//
//  HDU5667 - Sequence.cpp
//  數論
//
//  Created by Terry on 2018/9/29.
//  Copyright © 2018年 Terry. All rights reserved.
//

#include <stdio.h>
typedef long long LL;
long long read(){
    long long x = 0, f = 1;
    char ch=getchar();
    while(ch < '0' || ch > '9'){if(ch=='-') f = -1; ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0'; ch = getchar();}
    return x * f;
}
const int maxn = 3;
LL mod;
struct Matrix{
    long long int m[maxn][maxn];
}unit;
Matrix operator * (Matrix a, Matrix b){
    Matrix ret;
    LL x;
    int n = 3;
    for(int i = 0; i < n; ++i){
        for(int j = 0; j < n; ++j){
            x = 0;
            for(int k = 0; k < n; ++k){
                x += ((LL)a.m[i][k] * b.m[k][j]) % mod;
            }
            ret.m[i][j] = x % mod;
        }
    }
    return ret;
}
void init_unit(){
    // 單位矩陣
    for(int i = 0; i < maxn; ++i){
        unit.m[i][i] = 1;
    }
}
Matrix pow_mat(Matrix a, LL n){
    Matrix ans = unit;
    while (n) {
        if(n & 1){
            ans = ans * a;
        }
        a = a * a;
        n >>= 1;
    }
    return ans;
}
LL multi(LL a, LL b, LL Mod){
    // a * b % Mod
    LL ret = 0;
    while(b > 0){
        if(b & 1){
            ret = (ret + a) % Mod;
        }
        b >>= 1;
        a = (a << 1) % Mod;
    }
    return ret;
}

LL quick_mod(LL a, LL b, LL Mod){
    LL ans = 1;
    while(b){
        if(b & 1){
            ans = multi(ans, a, Mod);
            b--;
        }
        b /= 2;
        a = multi(a, a, Mod);
    }
    return ans;
}
int main(){
    init_unit();
    LL T = read();
    while (T--) {
        LL n = read();
        LL a = read();
        LL b = read();
        LL c = read();
        mod = read();
        if(n == 1){
            printf("1\n");
        }
        else if(n == 2){
            printf("%lld\n", quick_mod(a, b, mod));
        }
        else{
            if(a % mod == 0){
                printf("0\n");
                continue;
            }
            Matrix ans, A;
            A.m[0][0] = c; A.m[0][1] = 1; A.m[0][2] = 0;
            A.m[1][0] = 1; A.m[1][1] = 0; A.m[1][2] = 0;
            A.m[2][0] = 1; A.m[2][1] = 0; A.m[2][2] = 1;

            ans.m[0][0] = b; ans.m[0][1] = 0; ans.m[0][2] = b;

            mod--; // 費馬小定理
            A = pow_mat(A, n - 2);

            ans = ans * A;

            mod++;

            printf("%lld\n", quick_mod(a, ans.m[0][0]%(mod - 1), mod));
        }
    }
    return 0;
}