当前位置: 首页 > news >正文

算法能力提升之快速矩阵

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

题目描述

斐波那契数列:∗{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

代码部分:

#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. 矩阵乘法重载
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 modans[i][j] = (ans[i][j] + a[i][k] * b[k][j] % mod) % mod;}}}return ans;
}
2. 矩阵快速幂计算斐波那契数
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} 分别表示两个内层向量的元素。
vvl mat1;
mat1.push_back(vector<ll>{0, 1});  // 第一行
mat1.push_back(vector<ll>{1, 1});  // 第二行
http://www.dtcms.com/a/306376.html

相关文章:

  • PSO-TCN-BiLSTM-MATT粒子群优化算法优化时间卷积神经网络-双向长短期记忆神经网络融合多头注意力机制多特征分类预测/故障诊断Matlab实现
  • 电动车充电桩能耗实时监测解决方案
  • 【Java】批量生成Excel放入文件夹并打zip压缩包
  • LangChain 完全入门:5分钟搭建你的第一个AI智能体
  • 河南萌新联赛2025第(三)场:河南理工大学【补题】
  • 氯碱废水除钙镁金属离子
  • 无人机在复杂气流中,IMU 如何精准捕捉姿态变化以维持稳定?
  • WPFC#超市管理系统(3)商品管理
  • 今日行情明日机会——20250730
  • 【LeetCode】链表反转实现与测试
  • ansible巡检脚本
  • 2025年7月28日–7月29日 · AI 今日头条
  • 串口接收数据包(协议带帧头帧尾)的编程实现方法:1、数据包格式定义结构体2、使用队列进行数据接收、校验解包
  • centos7 aarch64上安装PostgreSQL14.3
  • 如何在生成式引擎优化(GEO)中取得成功
  • Java:高频面试知识分享1
  • 比特币挖矿的能源消耗和环保问题
  • 【Linux】重生之从零开始学习运维之备份恢复
  • CONTRASTIVE-KAN:一种用于稀缺标记数据的网络安全半监督入侵检测框架
  • Apache Kafka核心组件详解
  • click和touch事件触发顺序 糊里糊涂解决的奇怪bug
  • 开源 Arkts 鸿蒙应用 开发(十二)传感器的使用
  • WiFi连接简单流程
  • Linux命令---服务管理类命令
  • EPOLL 的用法
  • 报考民航安检员证需要具备哪些条件?
  • 50天50个小项目 (Vue3 + Tailwindcss V4) ✨ | VerifyAccountUi(验证码组件)
  • git本地仓库,工作区和暂存区的知识
  • SpringBoot之多环境配置全解析
  • 实现implements InitializingBean, DisposableBean 有什么用