佳佳的斐波那契
佳佳的斐波那契
佳佳对数学,尤其对数列十分感兴趣。
在研究完 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/
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/17266580.html