1643:【例 3】Fibonacci 前 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
5 1000
样例输出 #1
12
样例解释 #1
Fibonacci 数列前 5 项:1,1,2,3,5,和 S5=1+1+2+3+5=12。
12mod1000=12。
数据范围
对于 100% 的数据:
- 1≤n≤2×109
- 1≤m≤109+10
时空限制
- 时间限制:1000 ms
- 内存限制:524288 KB
注意:n 很大,不能直接求和。需要利用矩阵快速幂加速。
我们知道 Fibonacci 数列的递推关系:fn=fn−1+fn−2。前 n 项和 Sn=f1+f2+⋯+fn。也有递推关系:Sn=Sn−1+fn,但这样仍然需要递推。
更好的方法是将 Sn 也纳入状态向量。考虑状态向量:
$$\mathbf{F}_n = \begin{bmatrix}
f_{n+1} \\
f_n \\
S_n
\end{bmatrix}$$
我们希望找到转移矩阵 A,使得 Fn=A⋅Fn−1。
已知:
- fn+1=fn+fn−1
- fn=fn
- Sn=Sn−1+fn
但 $\mathbf{F}_{n-1} = \begin{bmatrix} f_n \\ f_{n-1} \\ S_{n-1} \end{bmatrix}$,我们需要用 fn,fn−1,Sn−1 表示 fn+1,fn,Sn:
- $f_{n+1} = 1 \cdot f_n + 1 \cdot f_{n-1} + 0 \cdot S_{n-1}$
- $f_n = 1 \cdot f_n + 0 \cdot f_{n-1} + 0 \cdot S_{n-1}$
- $S_n = 1 \cdot f_n + 0 \cdot f_{n-1} + 1 \cdot S_{n-1}$
所以转移矩阵为:
$$A = \begin{bmatrix}
1 & 1 & 0 \\
1 & 0 & 0 \\
1 & 0 & 1
\end{bmatrix}$$
验证:Fn=A⋅Fn−1。
初始状态 $\mathbf{F}_1 = \begin{bmatrix} f_2 \\ f_1 \\ S_1 \end{bmatrix} = \begin{bmatrix} 1 \\ 1 \\ 1 \end{bmatrix}$。
那么 Fn=An−1⋅F1。我们需要的是 Sn,即 Fn 的第三个分量。
因此,算法步骤:
- 构造 3×3 矩阵 A 和初始向量 F1。
- 计算 An−1(用矩阵快速幂)。
- 计算 Fn=An−1⋅F1。
- 输出 Fn 的第三个元素(即 Sn)模 m。
注意:当 n=1 时,n−1=0,A0 是单位矩阵,F1=[1,1,1]T,S1=1,正确。
另外,可以直接使用 2×2 矩阵包含和的信息,但 3×3 更清晰。
矩阵快速幂复杂度 O(33logn)=O(27logn),可以接受。
注意取模运算。