#jZCybttg060504. 1644:【例 4】佳佳的 Fibonacci

1644:【例 4】佳佳的 Fibonacci

1644:【例 4】佳佳的 Fibonacci

题目描述

佳佳对数学,尤其对数列十分感兴趣。在研究完 Fibonacci 数列后,他创造出许多稀奇古怪的数列。例如用 S(n)S(n) 表示 Fibonacci 前 nn 项和 modm\bmod m 的值,即 S(n)=(F1+F2+...+Fn)modmS(n)=(F_1+F_2+...+F_n) \bmod m,其中 F1=F2=1,Fi=Fi1+Fi2F_1=F_2=1, F_i=F_{i-1}+F_{i-2}。可这对佳佳来说还是小菜一碟。

终于,她找到了一个自己解决不了的问题。用 T(n)=(F1+2F2+3F3+...+nFn)modmT(n)=(F_1+2F_2+3F_3+...+nF_n) \bmod m 表示 Fibonacci 数列前 nn 项变形后的和 modm\bmod m 的值。

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

输入格式

输入数据包括一行,两个用空格隔开的整数 n,mn,m

输出格式

仅一行,T(n)T(n) 的值。

样例

样例输入 #1

5 5

样例输出 #1

1

样例解释 #1

  • Fibonacci 数列前 55 项:F1=1,F2=1,F3=2,F4=3,F5=5F_1=1, F_2=1, F_3=2, F_4=3, F_5=5
  • $T(5) = 1 \times 1 + 2 \times 1 + 3 \times 2 + 4 \times 3 + 5 \times 5 = 1 + 2 + 6 + 12 + 25 = 46$。
  • 46mod5=146 \bmod 5 = 1

数据范围

  • 对于 30%30\% 的数据,1n10001 \le n \le 1000
  • 对于 60%60\% 的数据,1m10001 \le m \le 1000
  • 对于 100%100\% 的数据,1n,m23111 \le n, m \le 2^{31}-1

时空限制

  • 时间限制:1000 ms
  • 内存限制:524288 KB

注意nn 很大,需要矩阵快速幂加速。我们需要计算 T(n)=i=1niFiT(n) = \sum_{i=1}^n i \cdot F_i

S(n)=i=1nFiS(n) = \sum_{i=1}^n F_iT(n)=i=1niFiT(n) = \sum_{i=1}^n i \cdot F_i

考虑递推关系:

  • Fn+1=Fn+Fn1F_{n+1} = F_n + F_{n-1}
  • Sn+1=Sn+Fn+1S_{n+1} = S_n + F_{n+1}
  • Tn+1=Tn+(n+1)Fn+1T_{n+1} = T_n + (n+1) F_{n+1}

我们希望将 Tn+1T_{n+1} 表示为 Tn,Fn,Fn1,Sn,nT_n, F_n, F_{n-1}, S_n, n 等的线性组合。但 nn 本身在变化,所以需要将 nn 也纳入状态向量。

定义状态向量:

$$\mathbf{X}_n = \begin{bmatrix} F_n \\ F_{n-1} \\ S_n \\ T_n \\ n \\ 1 \end{bmatrix}$$

注意:Fn1F_{n-1} 是必要的,因为递推需要前两项。nn11 是为了构造 (n+1)(n+1)

我们希望找到转移矩阵 AA,使得 Xn+1=AXn\mathbf{X}_{n+1} = A \cdot \mathbf{X}_n

写出 Xn+1\mathbf{X}_{n+1} 各分量:

  1. $F_{n+1} = 1 \cdot F_n + 1 \cdot F_{n-1} + 0 \cdot S_n + 0 \cdot T_n + 0 \cdot n + 0 \cdot 1$
  2. $F_n = 1 \cdot F_n + 0 \cdot F_{n-1} + 0 \cdot S_n + 0 \cdot T_n + 0 \cdot n + 0 \cdot 1$
  3. $S_{n+1} = S_n + F_{n+1} = 0 \cdot F_n + 0 \cdot F_{n-1} + 1 \cdot S_n + 0 \cdot T_n + 0 \cdot n + 0 \cdot 1 + F_{n+1}$,而 Fn+1F_{n+1} 已由第一行表示,所以 $S_{n+1} = 1 \cdot F_n + 1 \cdot F_{n-1} + 1 \cdot S_n + 0 \cdot T_n + 0 \cdot n + 0 \cdot 1$
  4. $T_{n+1} = T_n + (n+1) F_{n+1} = T_n + n F_{n+1} + F_{n+1}$。将 Fn+1F_{n+1} 用第一行表示,nn 用第五行表示,11 用第六行表示。所以:
    • $T_{n+1} = 0 \cdot F_n + 0 \cdot F_{n-1} + 0 \cdot S_n + 1 \cdot T_n + 0 \cdot n + 0 \cdot 1 + n F_{n+1} + F_{n+1}$
    • Fn+1=1Fn+1Fn1F_{n+1} = 1 \cdot F_n + 1 \cdot F_{n-1},所以 nFn+1=nFn+nFn1n F_{n+1} = n \cdot F_n + n \cdot F_{n-1},其中 nn 是第五个分量。
    • 因此,Tn+1T_{n+1} 的表达式包含 Fn,Fn1,Tn,nF_n, F_{n-1}, T_n, n 的线性组合,但 nn 乘以 FnF_nFn1F_{n-1} 不是线性组合(因为 nn 本身是变量)。实际上,我们需要将 nFnn F_n 视为整体?但状态向量中没有 nFnn F_n,所以不能直接线性表示。因此,我们需要增加状态分量,或者换一种思路。

另一种常见方法:注意到 $T(n) = \sum_{i=1}^n i F_i = n S_n - \sum_{i=1}^{n-1} S_i$。因为 $\sum_{i=1}^{n-1} S_i = \sum_{i=1}^{n-1} \sum_{j=1}^i F_j = \sum_{j=1}^{n-1} (n-j) F_j = n \sum_{j=1}^{n-1} F_j - \sum_{j=1}^{n-1} j F_j = n (S_n - F_n) - (T_n - n F_n) = n S_n - n F_n - T_n + n F_n = n S_n - T_n$。整理得:

i=1n1Si=nSnTn\sum_{i=1}^{n-1} S_i = n S_n - T_n

所以

Tn=nSni=1n1SiT_n = n S_n - \sum_{i=1}^{n-1} S_i

这个公式似乎没有简化问题。

更直接的方法:构造 4×44 \times 4 矩阵,包含 Fn,Fn1,nFn,(n1)Fn1F_n, F_{n-1}, n F_n, (n-1) F_{n-1} 之类的状态。但这样会复杂。

实际上,我们可以定义状态向量为:

$$\mathbf{Y}_n = \begin{bmatrix} F_n \\ F_{n-1} \\ n F_n \\ (n-1) F_{n-1} \\ 1 \end{bmatrix}$$

但递推时 nn 会变化。

另一种思路:考虑 TnT_n 的递推:

Tn=Tn1+nFnT_{n} = T_{n-1} + n F_n

FnF_n 有递推关系。所以我们需要同时维护 Fn,Fn1,Tn,nF_n, F_{n-1}, T_n, n。但 nn 每次加 11,可以表示为 n=(n1)+1n = (n-1) + 1,所以 nn 可以线性表示。

定义状态向量:

$$\mathbf{Z}_n = \begin{bmatrix} F_n \\ F_{n-1} \\ T_n \\ n \\ 1 \end{bmatrix}$$

Zn+1\mathbf{Z}_{n+1} 为:

  1. Fn+1=Fn+Fn1F_{n+1} = F_n + F_{n-1}
  2. Fn=FnF_n = F_n
  3. $T_{n+1} = T_n + (n+1) F_{n+1} = T_n + (n+1)(F_n + F_{n-1}) = T_n + n F_n + n F_{n-1} + F_n + F_{n-1}$
  4. n+1=n+1n+1 = n + 1
  5. 1=11 = 1

因此,转移矩阵 AA 满足 Zn+1=AZn\mathbf{Z}_{n+1} = A \cdot \mathbf{Z}_n,其中:

$$A = \begin{bmatrix} 1 & 1 & 0 & 0 & 0 \\ 1 & 0 & 0 & 0 & 0 \\ 1 & 1 & 1 & 1 & 0 \\ 0 & 0 & 0 & 1 & 1 \\ 0 & 0 & 0 & 0 & 1 \end{bmatrix}$$

解释:

  • 第一行:$F_{n+1} = 1 \cdot F_n + 1 \cdot F_{n-1} + 0 \cdot T_n + 0 \cdot n + 0 \cdot 1$
  • 第二行:$F_n = 1 \cdot F_n + 0 \cdot F_{n-1} + 0 \cdot T_n + 0 \cdot n + 0 \cdot 1$
  • 第三行:$T_{n+1} = 1 \cdot F_n + 1 \cdot F_{n-1} + 1 \cdot T_n + 1 \cdot n + 0 \cdot 1$(注意还需要 Fn+Fn1F_n + F_{n-1} 中的 FnF_nFn1F_{n-1} 系数已包含,但 nFnn F_nnFn1n F_{n-1} 中的 nn 来自第四列,所以第三行第四列系数为 11 表示 nn 的贡献?实际上,$T_{n+1} = T_n + (n+1)(F_n + F_{n-1}) = T_n + n F_n + n F_{n-1} + F_n + F_{n-1}$。所以 FnF_n 系数为 11(来自 FnF_n)和 nn 的系数为 11(来自 nFnn F_n)?但矩阵乘法是线性组合,不能有 nFnn F_n 这样的项,因为 nnFnF_n 是分开的分量。所以我们需要将 nFnn F_n 拆开?实际上,在状态向量中,nnFnF_n 是独立分量,乘积 nFnn F_n 不是分量的线性组合。因此,这个矩阵不能正确表示 Tn+1T_{n+1}

所以我们需要将 nFnn F_n 也作为状态分量。定义状态向量:

$$\mathbf{W}_n = \begin{bmatrix} F_n \\ F_{n-1} \\ n F_n \\ (n-1) F_{n-1} \\ T_n \\ 1 \end{bmatrix}$$

这样,每个分量都是线性的。递推关系:

  1. Fn+1=Fn+Fn1F_{n+1} = F_n + F_{n-1}
  2. Fn=FnF_n = F_n
  3. $(n+1) F_{n+1} = (n+1)(F_n + F_{n-1}) = n F_n + n F_{n-1} + F_n + F_{n-1}$
  4. nFn=nFnn F_n = n F_n(保持不变?实际上,(n+1)Fn+1(n+1) F_{n+1} 成为新的第三分量,原来的第三分量 nFnn F_n 在下一状态中变为 (n+1)Fn+1(n+1) F_{n+1} 的一部分,但我们需要递推关系)
  5. Tn+1=Tn+(n+1)Fn+1T_{n+1} = T_n + (n+1) F_{n+1}
  6. 1=11 = 1

这样,我们可以写出转移矩阵 AA。但状态向量有 66 个分量,矩阵为 6×66 \times 6

具体地,令 Wn=[Fn,Fn1,Un,Vn,Tn,1]T\mathbf{W}_n = [F_n, F_{n-1}, U_n, V_n, T_n, 1]^T,其中 Un=nFnU_n = n F_nVn=(n1)Fn1V_n = (n-1) F_{n-1}。则 Wn+1\mathbf{W}_{n+1} 为:

  • Fn+1=Fn+Fn1F_{n+1} = F_n + F_{n-1}
  • Fn=FnF_n = F_n
  • $U_{n+1} = (n+1) F_{n+1} = (n+1)(F_n + F_{n-1}) = n F_n + n F_{n-1} + F_n + F_{n-1} = U_n + (V_n + F_{n-1}) + F_n + F_{n-1}$,因为 Vn=(n1)Fn1V_n = (n-1) F_{n-1},所以 nFn1=Vn+Fn1n F_{n-1} = V_n + F_{n-1}。所以 Un+1=Un+Vn+Fn+2Fn1U_{n+1} = U_n + V_n + F_n + 2 F_{n-1}
  • Vn+1=nFn=UnV_{n+1} = n F_n = U_n
  • Tn+1=Tn+Un+1T_{n+1} = T_n + U_{n+1}(因为 Un+1=(n+1)Fn+1U_{n+1} = (n+1) F_{n+1}
  • 1=11 = 1

因此,转移矩阵 AA 为:

$$A = \begin{bmatrix} 1 & 1 & 0 & 0 & 0 & 0 \\ 1 & 0 & 0 & 0 & 0 & 0 \\ 1 & 2 & 1 & 1 & 0 & 0 \\ 1 & 0 & 1 & 0 & 0 & 0 \\ 1 & 2 & 1 & 1 & 1 & 0 \\ 0 & 0 & 0 & 0 & 0 & 1 \end{bmatrix}$$

验证:

  • 第一行:$F_{n+1} = 1 F_n + 1 F_{n-1} + 0 U_n + 0 V_n + 0 T_n + 0$
  • 第二行:$F_n = 1 F_n + 0 F_{n-1} + 0 U_n + 0 V_n + 0 T_n + 0$
  • 第三行:$U_{n+1} = 1 F_n + 2 F_{n-1} + 1 U_n + 1 V_n + 0 T_n + 0$
  • 第四行:$V_{n+1} = 1 F_n + 0 F_{n-1} + 1 U_n + 0 V_n + 0 T_n + 0$
  • 第五行:$T_{n+1} = 1 F_n + 2 F_{n-1} + 1 U_n + 1 V_n + 1 T_n + 0$
  • 第六行:1=0Fn+0Fn1+0Un+0Vn+0Tn+11 = 0 F_n + 0 F_{n-1} + 0 U_n + 0 V_n + 0 T_n + 1

初始状态:n=1n=1W1=[F1,F0,U1,V1,T1,1]T\mathbf{W}_1 = [F_1, F_0, U_1, V_1, T_1, 1]^T。但 Fibonacci 数列通常定义 F1=1,F0=0F_1=1, F_0=0。这里 F0=0F_0=0U1=1F1=1U_1 = 1 \cdot F_1 = 1V1=(11)F0=0V_1 = (1-1) F_0 = 0T1=1F1=1T_1 = 1 \cdot F_1 = 1。所以 W1=[1,0,1,0,1,1]T\mathbf{W}_1 = [1, 0, 1, 0, 1, 1]^T

那么 Wn=An1W1\mathbf{W}_n = A^{n-1} \cdot \mathbf{W}_1TnT_n 是第五个分量。

因此,算法步骤:

  1. 构造 6×66 \times 6 矩阵 AA 和初始向量 W1W_1
  2. 计算 B=An1B = A^{n-1}(矩阵快速幂)。
  3. 计算 Wn=BW1\mathbf{W}_n = B \cdot W_1
  4. 输出 Wn\mathbf{W}_n 的第五个元素(即 TnT_n)模 mm

注意 nn 可能为 11,此时 n1=0n-1=0A0A^0 是单位矩阵,W1\mathbf{W}_1 的第五个分量为 11,正确。

由于 nn 可达 23112^{31}-1,矩阵快速幂需要 O(63logn)=O(216logn)O(6^3 \log n) = O(216 \log n),可以接受。注意取模 mmmm 也可能很大,但矩阵元素在计算过程中取模即可。