【矩阵快速幂】 斐波那契前n项和

传送门

题意

给定 n和mod,求出前n 项斐波那契的和,结果模mod

数据范围

\(1\leq n\leq 2\times 10^{9}\)
\(1\leq mod\leq 1000000010\)

题解

数据范围很大只能接受 \(O (\sqrt{n})\) 或者 \(O(log n)\)
矩阵递推加速,f(n) 三维行向量表示为

\[\left( f(n) ,f(n+1) ,s(n) \right) \]

转移矩阵为:

\[\left( \begin{array}{l} 0 & 1 & 0 \\ 1 & 1 & 1 \\0 & 0 & 1\end{array} \right) \]

矩阵快速幂复杂度为\(O(3\times logn)\),满足要求

Code

#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, n) for(int i = a; i < n; i ++)
#define ll long long
int n, mod;

void mul(int f[4], int a[4][4])
{
    int t[4]; memset(t, 0, sizeof t);
    rep(i, 0, 4) rep(k, 0, 4)
            t[i]=(t[i]+ 1ll * f[k] * a[k][i])%mod;
    memcpy(f, t, sizeof t);
}
void mulself(int p[4][4])
{
    int t[4][4]; memset(t, 0, sizeof t);
    rep(i, 0, 4) rep(j, 0, 4) rep(k, 0, 4)
        t[i][j]=(t[i][j]+1ll * p[i][k] * p[k][j])%mod;
    memcpy(p, t, sizeof t);
}
int main()
{
    cin>>n>>mod;
    int p[4][4] = 
    {
        {0, 1, 0, 0},
        {1, 1, 1, 0},
        {0, 0, 1, 1},
        {0, 0, 0, 1}
    };
    int f[4] = {1, 1, 1, 0};
    int k = n - 1;
    while(k) 
    {
        if(k & 1) mul(f, p);
        mulself(p);
        k >>= 1;
    }
    cout<<( ( (1ll * n * f[2]) % mod - f[3]) % mod + mod) % mod<<endl;
    return 0;
}
posted @ 2021-03-30 22:05  Hyx'  阅读(93)  评论(0)    收藏  举报