算法能力提升之快速矩阵

今天还是给大家带来关于快速矩阵的算法思想,这部分类型题目还是重在解决时间复杂度过大的问题,同时要注意的是矩阵乘法重载的编写,这部分是关键。

题目描述

斐波那契数列:∗{F(1)=F(2)=1F(n)=F(n−1)+F(n−2)​​n>2,n∈N∗​

给定一个正整数 N,求F(N)在模109+7 下的值。

输入描述

第 1 行为一个整数 T,表示测试数据数量。

接下来的 TT 行每行包含一个正整数 N。

1≤T≤104,1≤N≤1018。

输出描述

输出共 T 行,每行包含一个整数,表示答案。

输入案例:

复制代码
6
1
2
3
4
5
1000000000

输出案例:

复制代码
1
1
2
3
5
21

代码部分:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const int mod=1e9+7;
using vvl=vector<vector<ll>>;ll n;
vvl operator*(const vvl &a,const vvl &b){
    vvl ans(2,vector<ll>(2,0));
    for(int i=0;i<2;i++){
        for(int j=0;j<2;j++){
            for(int k=0;k<2;k++){
                ans[i][j]=(ans[i][j]+a[i][k]*b[k][j]%mod)%mod;
            }
        }
    }
    return ans;
}
ll solve(){
    cin>>n;
    vvl mat1={{0,1},{1,1}},matans={{1,0},{0,1}};//单位矩阵
    while(n){
        if(n&1)matans=matans*mat1;
        mat1=mat1*mat1;n>>=1;
    }
    return 1*matans[0][1];}
int main(){
    int t=1;
    cin>>t;
    while(t--){
        cout<<solve()<<'\n';
    }
    return 0;
}

核心原理:矩阵表示斐波那契递推

斐波那契数列的递推关系可以用矩阵乘法表示:

F(n) F(n−1)​\]=\[11​ 10​\]×\[F(n−1) F(n−2)​

进一步推广,通过连续的矩阵乘法可以得到:

F(n)F(n−1)​\]=\[11 ​10​\]n−2×\[F(2)F(1)​\]=\[11​ 10​\]n−2×\[11​

代码解析:

1. 矩阵乘法重载
cpp 复制代码
using vvl = vector<vector<ll>>;  // 定义vvl为二维long long向量(矩阵)

// 重载矩阵乘法运算符
vvl operator*(const vvl &a, const vvl &b) {
    vvl ans(2, vector<ll>(2, 0));  // 结果矩阵(2x2)
    for (int i = 0; i < 2; i++) {
        for (int j = 0; j < 2; j++) {
            for (int k = 0; k < 2; k++) {
                // 矩阵乘法:ans[i][j] = sum(a[i][k] * b[k][j]) mod mod
                ans[i][j] = (ans[i][j] + a[i][k] * b[k][j] % mod) % mod;
            }
        }
    }
    return ans;
}
2. 矩阵快速幂计算斐波那契数
cpp 复制代码
ll solve() {
    cin >> n;  // 输入N
    
    // 递推矩阵:[[0,1],[1,1]](与标准形式等价,只是行列顺序调整)
    vvl mat1 = {{0, 1}, {1, 1}};
    // 单位矩阵:初始结果矩阵(矩阵乘法的"1")
    vvl matans = {{1, 0}, {0, 1}};
    
    // 矩阵快速幂:计算mat1的n次幂(通过二进制分解)
    while (n) {
        if (n & 1) {  // 若当前二进制位为1,将mat1乘入结果
            matans = matans * mat1;
        }
        mat1 = mat1 * mat1;  // 矩阵自乘(指数翻倍)
        n >>= 1;  // 右移一位,处理下一个二进制位
    }
    
    // 返回F(n):根据矩阵乘法结果推导,此处取matans[0][1]
    return 1 * matans[0][1];
}
  • (2, vector<ll>(2, 0)):调用 vector 的构造函数,参数表示 "创建一个包含 2 个元素的外层向量,每个元素都是 vector<ll>(2, 0)"。
    • 内层 vector<ll>(2, 0) 表示 "创建一个包含 2 个元素的 long long 向量,每个元素初始化为 0"。

因此,vvl ans(2, vector<ll>(2, 0)) 的实际效果是:

创建一个 2 行 2 列的二维向量(矩阵),所有元素初始化为 0,等价于:

复制代码
vector<vector<ll>> ans(2, vector<ll>(2, 0));  // 没有别名时的写法

3. 为什么可以 vvl mat1 = {``{0, 1}, {1, 1}} 这样初始化?

  • {``{0, 1}, {1, 1}} 是一个嵌套的初始化列表:外层列表 { {0,1}, {1,1} } 表示外层向量的两个元素。内层列表 {0,1}{1,1} 分别表示两个内层向量的元素。
cpp 复制代码
vvl mat1;
mat1.push_back(vector<ll>{0, 1});  // 第一行
mat1.push_back(vector<ll>{1, 1});  // 第二行
相关推荐
爱代码的小黄人1 小时前
利用劳斯判据分析右半平面极点数量的方法研究
算法·机器学习·平面
今天也好累4 小时前
C 语言基础第16天:指针补充
java·c语言·数据结构·笔记·学习·算法
大千AI助手5 小时前
直接偏好优化(DPO):原理、演进与大模型对齐新范式
人工智能·神经网络·算法·机器学习·dpo·大模型对齐·直接偏好优化
小妖同学学AI5 小时前
deepseek+飞书多维表格 打造小红书矩阵
人工智能·矩阵·飞书
Swiler6 小时前
数据结构第3问:什么是线性表?
数据结构
实心儿儿6 小时前
数据结构——单链表1
数据结构
徐小夕6 小时前
再也不怕看不懂 GitHub 代码!这款AI开源项目,一键生成交互架构图
前端·算法·github
再卷也是菜6 小时前
数据结构(7)单链表算法题OVA
数据结构
SirLancelot17 小时前
数据结构-Set集合(一)Set集合介绍、优缺点
java·开发语言·数据结构·后端·算法·哈希算法·set
YouQian7727 小时前
label 拓扑排序
数据结构·算法