具有结合律,不具有交换律。
一般结合快速幂使用。

AcWing 1303. 斐波那契前 n 项和

大家都知道 Fibonacci 数列吧,f1=1,f2=1,f3=2,f4=3,…,fn=fn−1+fn−2。
现在问题很简单,输入 n 和 m,求 fn 的前 n 项和 Snmodm。
输入格式
共一行,包含两个整数 n 和 m。
输出格式
输出前 n 项和 Snmodm 的值。
数据范围
1≤n≤2000000000,
1≤m≤1000000010
输入样例:
5 1000
输出样例:
12

思路:
构造矩阵

  1. F[n] = [f(n), f(n + 1), s(n)]
  2. F[n + 1] = [f(n + 1), f(n + 2), s(n + 1)]
  3. F[n + 1] = F[n] * [[0, 1, 0], [1, 1, 1], [0, 0, 1]];
  4. A = [[0, 1, 0], [1, 1, 1], [0, 0, 1]]
  1. import java.util.*;
  2. public class Main {
  3. static int n, m;
  4. public static void main(String[] args) {
  5. Scanner sc = new Scanner(System.in);
  6. n = sc.nextInt();
  7. m = sc.nextInt();
  8. long[][] A = {{0, 1, 0}, {1, 1, 1}, {0, 0, 1}};
  9. long[][] F = {{1, 1, 1}};
  10. A = qmi(A, n - 1);
  11. F = matrixMul(F, A);
  12. System.out.println(F[0][2]);
  13. }
  14. static long[][] qmi(long[][] b, int c) {
  15. int len = b.length;
  16. long[][] res = new long[len][len];
  17. for (int i = 0; i < len; i++)
  18. res[i][i] = 1;
  19. while (c > 0) {
  20. if ((c & 1) == 1)
  21. res = matrixMul(res, b);
  22. c >>= 1;
  23. b = matrixMul(b, b);
  24. }
  25. return res;
  26. }
  27. static long[][] matrixMul(long[][] a, long[][] b) {
  28. int row = a.length, col = b[0].length, t = b.length;
  29. long[][] res = new long[row][col];
  30. for (int k = 0; k < t; k++) {
  31. for (int i = 0; i < row; i++) {
  32. for (int j = 0; j < col; j++) {
  33. res[i][j] = (res[i][j] + (a[i][k] * b[k][j])) % m;
  34. }
  35. }
  36. }
  37. return res;
  38. }
  39. }

AcWing 1304. 佳佳的斐波那契

佳佳对数学,尤其对数列十分感兴趣。
在研究完 Fibonacci 数列后,他创造出许多稀奇古怪的数列。
例如用 S(n) 表示 Fibonacci 前 nn 项和 modmmodm 的值,即 S(n)=(F1+F2+…+Fn)modm,其中 F1=F2=1,Fi=Fi−1+Fi−2。
可这对佳佳来说还是小菜一碟。
终于,她找到了一个自己解决不了的问题。
用 T(n)=(F1+2F2+3F3+…+nFn)modm 表示 Fibonacci 数列前 n 项变形后的和 modm 的值。
现在佳佳告诉你了一个 n 和 m,请求出 T(n) 的值。
输入格式
共一行,包含两个整数 n 和 m。
输出格式
共一行,输出 T(n) 的值。
数据范围
1≤n,m≤231−1
输入样例:
5 5
输出样例:
1
样例解释
T(5)=(1+2×1+3×2+4×3+5×5)mod5=1

思路:
递推公式 + 矩阵乘法+ 快速幂

  1. // 如何表示 T(n)
  2. T(n) = f(1) + 2f(2) + ... + nf(n)
  3. nS(n) - T(n) = (n - 1)f(1) + (n - 2)f(2) + ... + f(n - 1)
  4. (n + 1)S(n + 1) - T(n + 1) = n(1) + (n - 1)f(2) + ... + 2f(n - 1) + f(n)
  5. P(n) = nS(n) - T(n)
  6. p(n + 1) = P(n) + S(n)
  7. 故可设
  8. F(n) = [f(n) f(n+1) S(n) P(n)]
  9. F(n + 1) = [f(n+1) f(n+2) S(n+1) P(n+1)] = F(n) *
  10. [
  11. [0 1 0 0]
  12. [1 1 1 0]
  13. [0 0 1 1]
  14. [0 0 0 1]
  15. ]
  1. import java.util.*;
  2. public class Main {
  3. static int n, m;
  4. public static void main(String[] args) {
  5. Scanner sc = new Scanner(System.in);
  6. n = sc.nextInt();
  7. m = sc.nextInt();
  8. long[][] A = {
  9. {0, 1, 0, 0},
  10. {1, 1, 1, 0},
  11. {0, 0, 1, 1},
  12. {0, 0, 0, 1}
  13. };
  14. long[][] F = {
  15. {1, 1, 1, 0}
  16. };
  17. A = qmi(A, n - 1);
  18. F = matrixMul(F, A);
  19. System.out.println(((n * F[0][2] - F[0][3]) % m + m) % m);
  20. }
  21. static long[][] qmi(long[][] a, int b) {
  22. int len = a.length;
  23. long[][] res = new long[len][len];
  24. for (int i = 0; i < len; i++)
  25. res[i][i] = 1;
  26. while (b > 0) {
  27. if ((b & 1) == 1)
  28. res = matrixMul(res, a);
  29. b >>= 1;
  30. a = matrixMul(a, a);
  31. }
  32. return res;
  33. }
  34. static long[][] matrixMul(long[][] a, long[][] b) {
  35. int row = a.length, col = b[0].length, t = a[0].length;
  36. long[][] res = new long[row][col];
  37. for (int k = 0; k < t; k++) {
  38. for (int i = 0; i < row; i++) {
  39. for (int j = 0; j < col; j++) {
  40. res[i][j] = (res[i][j] + a[i][k] * b[k][j]) % m;
  41. }
  42. }
  43. }
  44. return res;
  45. }
  46. }