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

HDU 5667 Sequence【矩陣快速冪+費馬小定理】

題目連結:

題意:

Lcomyn 是個很厲害的選手,除了喜歡寫17kb+的程式碼題,偶爾還會寫數學題.他找到了一個數列:

fn=

1,ab,abfcn1fn2,n=1n=2otherwise
給定各個數,求fn

分析:

可以發現最後都是a的倍數,這樣我們讓fn對a取對數,令tn=logafn方程就轉化為b+ctn1+tn2,這樣利用矩陣快速冪直接算冪數,最後快速冪一下就可以了。
注意:

  • 由費馬小定理可知,ab%p=ab/(p1)(p1)+b%(p1)%p=ab/(p1)(p1)%pab%(p1)%p=ab%(p1)%p,所以矩陣快速冪的模應該為p
    1
  • 特別注意a%p==0的時候,答案應該為0。

程式碼:

#include<cstdio>
const int N = 105;
int mod = 1e9 + 7;
struct Matrix
{
    int row,cal;
    long long  m[N][N];
};
Matrix init(Matrix a, long long t)
{
    for(int i = 0; i < a.row; i++)
        for(int j = 0; j < a.cal; j++)
            a.m[i][j] = t;
    return
a; } Matrix mul(Matrix a,Matrix b) { Matrix ans; ans.row = a.row, ans.cal = b.cal; ans = init(ans,0); for(int i = 0; i < a.row; i++) for(int j = 0; j < b.cal; j++) for(int k = 0; k < a.cal; k++) ans.m[i][j] = (ans.m[i][j] + a.m[i][k] * b.m[k][j])%mod; return
ans; } int quickpow(int a, int b, int mod) { int ans = 1; for(;b;b >>= 1, a = a * 1ll * a % mod){ if(b & 1) ans = ans * 1ll * a % mod; } return ans; } int quick_pow(long long k, int b, Matrix A) { if(k < 0) return 0; if(k == 0) return b; Matrix I; I.row = 3, I.cal = 1; I = init(I, 0); I.m[0][0] = 1; I.m[1][0] = b; I.m[2][0] = 0; while(k){ if(k & 1) I = mul(A, I); A = mul(A, A); k>>=1; } return I.m[1][0]%mod; } int main (void) { int T;scanf("%d", &T); while(T--){ int a, b, c, p; long long n; scanf("%I64d%d%d%d%d", &n, &a,&b, &c, &p); if(a % p == 0){printf("0\n");continue;} mod = p - 1; Matrix A; A.row = 3, A.cal = 3; A = init(A, 0); A.m[0][0] = A.m[2][1] = A.m[1][2] = 1; A.m[1][0] = b;A.m[1][1] = c; int res = quick_pow(n - 2, b, A); printf("%d\n", quickpow(a, res, p)); } }