CoderXL's Blog

Back

P1962 斐波那契数列Blur image

好多同学看到这道题的名字,都被勾引过去了,实际上并不简单呢。


朴素做法是递推,复杂度 O(n)O(n). 然而这道题的 nn 达到 26310192^{63} \approx 10^{19},递推只能拿 60 pts.


一些同学想到了通项公式:

15[(1+52)n(152)n]{1\over \sqrt5}\left[\left({1+\sqrt 5 \over 2}\right)^n-\left({1-\sqrt 5 \over 2}\right)^n\right]

然而由于涉及实数,存在浮点精度问题,因此除非你手写高精度浮点,否则也无法通过。


想一下为什么这道题出现在 P3390 【模板】矩阵快速幂 之后?正如上一篇题解中所说,一些情况下我们需要计算方阵的幂,而求解线性递推数列就是其中之一。

如果用 FiF_i 表示斐波那契数列的第 ii 项,则 F0=0, F1=1F_0=0,\ F_1=1,且 Fi=Fi1+Fi2, i{2,3,}F_{i}=F_{i-1}+F_{i-2},\ i\in\{2,3,\dots\}.

考虑向量 [FiFi1]\begin{bmatrix*} F_i\\ F_{i-1} \end{bmatrix*},我们可以把上述递推公式写成矩阵向量乘法的形式:

[Fi+1Fi]=[1110][FiFi1] = ⁣= ⁣=记作 A[FiFi1]\begin{bmatrix*} F_{i+1}\\F_i \end{bmatrix*} = \begin{bmatrix*} 1 &1 \\ 1 &0\end{bmatrix*} \begin{bmatrix*} F_i\\F_{i-1} \end{bmatrix*} ~\overset{\text{记作}}{=\!=\!=}~ \boldsymbol{A} \begin{bmatrix*} F_i\\F_{i-1} \end{bmatrix*}

因此,求解 FnF_n 就可以看作使用 An1\boldsymbol{A}^{n-1} 去左乘 [F1F0]=[10]\begin{bmatrix*} F_1\\ F_{0} \end{bmatrix*}=\begin{bmatrix*} 1\\ 0 \end{bmatrix*},可以 O(logn)O(\log n) 地求解。

特别地,由于 [10]\begin{bmatrix*} 1\\ 0 \end{bmatrix*} 可以看作取 An1\boldsymbol{A}^{n-1} 的第一列,因此直接计算 An1\boldsymbol{A}^{n-1} 即可,然后取左上角的元素。


ll n;
struct Matrix; // Matrix 定义见前一篇题解
Matrix a,ans;

int main()
{
	cin>>n;
    n--;
    a.m=a.n=ans.m=ans.n=2;
    a[1][1]=a[1][2]=a[2][1]=ans[1][1]=ans[2][2]=1; // 初始化矩阵,a 为 A 矩阵,ans 为单位矩阵
    while(n)
    {
        if(n&1)
        {
            ans*=a;
        }
        a*=a;
        n>>=1;
    }
    cout<<ans[1][1]%Mod;
    return 0;
}
cpp
P1962 斐波那契数列
https://blog.leosrealms.top/blog/miscellaneous/daily-luogu/2026-03-30-p1962-fibonacci-sequence
Author CoderXL
Published at 2026年3月30日
Comment seems to stuck. Try to refresh?✨