• AcWing 1304. 佳佳的斐波那契


    题目传送门

    一、矩阵推导过程

    \[\because S_n=F_1+F_2+⋯+F_n=\sum_{i=1}^{n}F_i \\ T_n=F_1+2*F_2+...+nF_n=\sum_{i=1}^{n}iF_i\]

    我们需要利用\(T_n\)构造新的数列,从而消去变量\(i\),最后再反解出\(T_n\)

    \[\therefore nS_n-T_n=(n-1)F_1+(n-2)F_2+...+F_{n-1} \]

    \(C_n=nS_n-T_n\)

    \[\therefore C_n=(n-1)F_1+(n-2)F_2+...+F_{n-1} \]

    \[C_{n+1}=nF_1+(n-1)F_2+...+F_{n} \]

    下式减上式

    \[C_{n+1}-C_n=F_1+F_2+F_3+...+F_n=S_n \]

    于是我们只需维护如下矩阵即可

    \[\begin{pmatrix} f_{n+1} & f_n & s_n & c_n \end{pmatrix} \]

    有如下等式:

    \[\begin{pmatrix} f_{n+1} & f_n & s_n & c_n \end{pmatrix} \times \begin{pmatrix} 1 & 1 & 1 & 0 \\ 1 & 0 & 0 & 0 \\ 0 & 0 & 1 & 1 \\ 0 & 0 & 0 & 1 \end{pmatrix}= \begin{pmatrix} f_{n+2} & f_{n+1} & s_{n+1} & c_{n+1} \end{pmatrix} \]

    然后直接使用矩阵快速幂便可以求解

    后来的\(T_n=nS_n-C_n\)

    下面两种方法都是可以完成递推的:

    \[\begin{pmatrix} f_{1} & f_{0} & s_{0} & c_{0} \\ \end{pmatrix} = \begin{pmatrix} 1 & 0 & 0& 0 \end{pmatrix} \]

    此时要取\(n\)次幂。

    \[\begin{pmatrix} f_{2} & f_{1} & s_{1} & c_{1} \end{pmatrix} = \begin{pmatrix} 1 & 1 & 1 & 0 \end{pmatrix} \]

    此时要取\(n-1\)次幂。

    二、实现代码I

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    
    const int N = 4;
    int n, mod;
    
    //矩阵乘法
    void mul(LL a[][N], LL b[][N], LL c[][N]) {
        LL t[N][N] = {0};
        for (LL i = 0; i < N; i++) {
            for (LL j = 0; j < N; j++)
                for (LL k = 0; k < N; k++)
                    t[i][j] = (t[i][j] + (a[i][k] * b[k][j]) % mod) % mod;
        }
        memcpy(c, t, sizeof t);
    }
    //矩阵快速幂
    // a: 初始矩阵,同时也是结果矩阵
    // b:  构建的向量矩阵,需要它进行多个幂次方计算
    // k:  多少次方
    void qmi(LL a[][N], LL b[][N], int k) {
        for (int i = k; i; i >>= 1) {
            if (i & 1) mul(a, b, a); // a*b-->a
            mul(b, b, b);            // b*b->b
        }
    }
    int main() {
        LL a[N][N] = {1, 0, 0, 0};
        LL b[N][N] = {
            {1, 1, 1, 0},
            {1, 0, 0, 0},
            {0, 0, 1, 1},
            {0, 0, 0, 1}};
        cin >> n >> mod;
        qmi(a, b, n);
    
        LL t = (n * a[0][2]) - a[0][3];
        t = (t % mod + mod) % mod;
        printf("%lld\n", t);
        return 0;
    }
    

    三、实现代码II

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    
    const int N = 4;
    int n, mod;
    
    //矩阵乘法
    void mul(LL a[][N], LL b[][N], LL c[][N]) {
        LL t[N][N] = {0};
        for (LL i = 0; i < N; i++) {
            for (LL j = 0; j < N; j++)
                for (LL k = 0; k < N; k++)
                    t[i][j] = (t[i][j] + (a[i][k] * b[k][j]) % mod) % mod;
        }
        memcpy(c, t, sizeof t);
    }
    //矩阵快速幂
    // a: 初始矩阵,同时也是结果矩阵
    // b:  构建的向量矩阵,需要它进行多个幂次方计算
    // k:  多少次方
    void qmi(LL a[][N], LL b[][N], int k) {
        for (int i = k; i; i >>= 1) {
            if (i & 1) mul(a, b, a); // a*b-->a
            mul(b, b, b);            // b*b->b
        }
    }
    int main() {
        LL a[N][N] = {1, 1, 1, 0}; //此处声明为二维,可以少写一个一维乘二维的函数
        //这里只是第一行,其它行默认值是0,其实,其它行是啥都一样,因为计算了也不读取,没用
        LL b[N][N] = {
            {1, 1, 1, 0},
            {1, 0, 0, 0},
            {0, 0, 1, 1},
            {0, 0, 0, 1}};
        cin >> n >> mod;
        qmi(a, b, n - 1);
    
        LL t = (n * a[0][2]) - a[0][3];
        t = (t % mod + mod) % mod;
        printf("%lld\n", t);
        return 0;
    }
    
  • 相关阅读:
    汉诺塔问题合集之汉诺塔6
    汉诺塔问题合集之汉诺塔5
    接口和抽象类有什么区别
    Java版本:JDK8的十大新特性介绍
    Linux的常用命令
    行为型模式——策略模式
    shell 后台执行命令
    ORA-01034:oracle不可用 的解决方法
    ORA-12514 TNS 监听程序当前无法识别连接描述符中请求服务 的解决方法
    linux下启动oracle
  • 原文地址:https://www.cnblogs.com/littlehb/p/16342848.html
Copyright © 2020-2023  润新知