佳佳的斐波那契

佳佳的斐波那契

佳佳对数学,尤其对数列十分感兴趣。

在研究完 Fibonacci 数列后,他创造出许多稀奇古怪的数列。

例如用 $S(n)$ 表示 Fibonacci 前 $n$ 项和 $\text{mod} \ m$ 的值,即 $S(n)=(F_1+F_2+…+F_n) \bmod m$,其中 $F_1=F_2=1,F_i=F_{i−1}+F_{i−2}$。

可这对佳佳来说还是小菜一碟。

终于,她找到了一个自己解决不了的问题。

用 $T(n)=(F_1+2F_2+3F_3+\ldots+nF_n) \bmod m$ 表示 Fibonacci 数列前 $n$ 项变形后的和 $\text{mod} \ m$ 的值。

现在佳佳告诉你了一个 $n$ 和 $m$,请求出 $T(n)$ 的值。

输入格式

共一行,包含两个整数 $n$ 和 $m$。

输出格式

共一行,输出 $T(n)$ 的值。

数据范围

$1 \leq n,m \leq {2}^{31}−1$

输入样例:

5 5

输出样例:

1

样例解释

$T(5)=(1+2 \times 1+3 \times 2+4 \times 3+5 \times 5) \bmod 5=1$

 

解题思路

  首先我们知道如果要求斐波那契数列的前$n$项和$S_n = \sum\limits_{i=1}^{n}{f_i}$,可以通过构造向量$F_n = \begin{bmatrix} f_n & f_{n+1} & S_n \end{bmatrix}$,以及矩阵$A = \begin{bmatrix} 0 & 1 & 0 \\ 1 & 1 & 1 \\ 0 & 0 & 1 \end{bmatrix}$,得到$F_{n+1} = F_n \times A$,从而通过递推与矩阵乘法的结合律得到$F_n = F_0 \times A^n$,这样就可以得到$S_n$了。

  对于这题的$T_n$如果直接构造矩阵$A$的话会发现元素含有变量,这样每一项的$A$都不一样,无法得到$A^n$这种形式。尝试构造$$P_n = n \cdot S_n - T_n = (n-1) \cdot f_1 +  (n-2) \cdot f_2 + \cdots + f_{n-1} \tag{1}$$$$P_{n+1} = (n+1) \cdot S_{n+1} - T_{n+1} = n \cdot f_1 + (n-1) \cdot f_2 + \cdots + f_{n} \tag{2}$$

  $(2)-(1)$得到$P_{n+1} - P_{n} = f_1 + f_2 + \ldots + f_n = S_n$,即$P_{n} = P_{n-1} + S_{n}$。同时根据$P_n = n \cdot S_n - T_n$得到$T_{n} = nS_n - P_n$,因此可以构造$F_n = \begin{bmatrix} f_n & f_{n+1} & S_n & P_n \end{bmatrix}$,$A = \begin{bmatrix} 0 & 1 & 0 & 0 \\ 1 & 1 & 1 & 0 \\ 0 & 0 & 1 & 1 \\ 0 & 0 & 0 & 1 \end{bmatrix}$,那么就会有$$\begin{bmatrix} f_n & f_{n+1} & S_n & P_n \end{bmatrix} \times \begin{bmatrix} 0 & 1 & 0 & 0 \\ 1 & 1 & 1 & 0 \\ 0 & 0 & 1 & 1 \\ 0 & 0 & 0 & 1 \end{bmatrix} = \begin{bmatrix} f_{n+1} & f_{n+2} & S_{n+1} & P_{n+1} \end{bmatrix} = F_{n+1}$$

  因此有递推式$F_n = F_0 \times A^n$,其中$F_0 = \begin{bmatrix} 0 & 1 & 0 & 0 \end{bmatrix}$。

  AC代码如下,时间复杂度为$O(4^3 \times \log{n})$:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 int mod;
 5 int a[4][4] = {
 6     {0, 1, 0, 0},
 7     {1, 1, 1, 0},
 8     {0, 0, 1, 1},
 9     {0, 0, 0, 1}
10 };
11 
12 void mul(int c[][4], int a[][4], int b[][4]) {
13     int tmp[4][4] = {0};
14     for (int i = 0; i < 4; i++) {
15         for (int j = 0; j < 4; j++) {
16             for (int k = 0; k < 4; k++) {
17                 tmp[i][j] = (tmp[i][j] + 1ll * a[i][k] * b[k][j]) % mod;
18             }
19         }
20     }
21     memcpy(c, tmp, sizeof(tmp));
22 }
23 
24 int main() {
25     int n;
26     scanf("%d %d", &n, &mod);
27     int f[4][4] = {0, 1, 0, 0}, k = n;
28     while (k) {
29         if (k & 1) mul(f, f, a);
30         mul(a, a, a);
31         k >>= 1;
32     }
33     printf("%d", ((1ll * n * f[0][2] - f[0][3]) % mod + mod) % mod);
34     
35     return 0;
36 }

 

参考资料

  AcWing 1304. 佳佳的斐波那契(算法提高课):https://www.acwing.com/video/715/

posted @ 2023-03-28 20:26  onlyblues  阅读(38)  评论(0编辑  收藏  举报
Web Analytics