/** *stratege: 构造矩阵 A = |1 1| * |1 0| * 矩阵快速幂,二分求和 *status: johnsondu B Accepted 252 KB 15 ms C++ 3113 B * */ #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; typedef __int64 LLD ; struct Matrix { LLD mat[2][2] ; }; Matrix tmp, unit, res ; LLD K, B, n, M ; Matrix a1, a2, a3 ; Matrix Multi (Matrix a, Matrix b) //两矩阵相乘 { Matrix c ; for (int i = 0; i < 2;i ++) for (int j = 0; j < 2; j ++) { c.mat[i][j] = 0 ; for (int k = 0; k < 2; k ++) c.mat[i][j] += (LLD)a.mat[i][k]*b.mat[k][j] ,c.mat[i][j] %= M ; //矩阵相乘时,需要防止溢出 } return c ; } Matrix power (LLD p) //求出a1 = A^b { Matrix tp = unit ; Matrix tr = tmp ; while (p) { if (p&1) { tr = Multi (tr, tp) ; p -- ; continue ; } tp = Multi (tp, tp) ; p >>= 1 ; } return tr ; } Matrix power1 (LLD p) //求出a2 = A^k { Matrix tp = a2 ; Matrix tr = tmp ; while (p) { if (p&1) { tr = Multi (tr, tp) ; p -- ; continue ; } tp = Multi (tp, tp) ; p >>= 1 ; } return tr ; } Matrix add (Matrix a, Matrix b) //矩阵相加 { Matrix c ; for (int i = 0; i < 2; i ++) for (int j = 0; j < 2; j ++) c.mat[i][j] = (a.mat[i][j] + b.mat[i][j]) % M ; return c ; } void init () { unit.mat[0][0] = 1 ; //初始化矩阵 unit.mat[0][1] = 1 ; unit.mat[1][0] = 1 ; unit.mat[1][1] = 0 ; tmp.mat[0][0] = 1 ; //单位矩阵 tmp.mat[0][1] = 0 ; tmp.mat[1][0] = 0 ; tmp.mat[1][1] = 1 ; a1 = power (B) ; //由题意有ans = A^b + A^(k+b) + A^(2k+b) + ... + A^((n-1)k + b) a2 = power (K) ; //由此得出 a1 = A^b, a2 = A^k, 所以有ans = a1 * (E + a2^1 + a2^2 + ... + a2^(n-1)) ; } Matrix MatrixSum (LLD p) //求出E + a2^1 + a2^2 + ... + a2^(n-1) { if (p == 1) //注意,此时p==1时,基为a2 = A^k return a2 ; Matrix tm, tr ; tm = MatrixSum (p/2) ; if (p & 1) { tr = power1 (p/2+1) ; tm = add (tm, Multi (tm, tr)) ; tm = add (tm, tr) ; } else { tr = power1 (p/2) ; tm = add (tm, Multi (tm, tr)) ; } return tm ; } void output () //输出 { if (n == 1) { printf ("%I64d\n", a1.mat[0][1]) ; return ; } if (n == 0) { printf ("0\n") ; return ; } Matrix ans = MatrixSum (n-1) ; //因为是求出0~n-1, 此处先求出1~n-1 ans = add (ans, tmp) ; //再求出与单位矩阵的和 ans = Multi (ans, a1) ; //ans = a1 * (E + a2^1 + a2^2 + ... + a2^(n-1)) printf ("%I64d\n", ans.mat[0][1] % M) ; //输出 } int main() { while (scanf ("%I64d%I64d%I64d%I64d", &K, &B, &n, &M) != EOF) { init () ; output () ; } return 0; }