算法分类整理+模板①:矩阵快速幂

一直有一个想法,感觉自己很多基础算法不是很扎实,想要找个机会写一些算法的整理,顺便自己总结一些实用的模板。

最近偶然在训练赛中连续做了2道思维+矩阵快速幂的题目,碰巧有时间,就以矩阵快速幂作为这个系列博客的开始吧。

 

如果想要了解矩阵快速幂,首先要了解什么叫做快速幂。

举个例子,如果让你求2^10的值,一个for循环可以轻松地解决问题,但是如果是2^10000000000000呢?

且不管这个值能否表示出来,单单说for循环的时间复杂度O(n)就注定不能直接暴力求解。

当然,为了求得这个解,我们一般要求答案对于某个数取模,常用的MOD值有10007,1000000007。

由此,我们可以看出,当问题存在超时+取模的限制时,我们需要一种新的算法,即快速幂。

快速幂是基于二分思想的一种时间复杂度为O(lgn)的算法。

我们可以考虑一个例子,如果要求2^10的值,我们能否这样算:

首先把2^10分解成(2^5)*(2^5),其次把2^5分解成2*(2^4),然后将2^4分成(2^2)*(2^2),最后把2^2变成2*2。

这样,我们就将2^10变成了:(2*(2*2)^2)^2。这样我们只需要计算4次乘法就可以得到2^10的值,而线性的算法需要10次,快速幂进行了极大地优化。

一般地,对于a^b来说,当b为偶数时,我们可以写成(a^(b/2))^2;当b为奇数时,可以写成a*(a^(b-1))。

所以,经过快速幂算法优化后的quick_pow计算只需要log(b)次!b越大,这个优化就越明显!

模板代码如下:

 

#include <stdio.h>
#include <iostream>
#define MOD 1000000007
typedef long long int LL
using namespace std;
LL quick_pow(int a,int b){LL res=1;while(b){if(b&1)res=((a%MOD)*(res%MOD))%MOD;res=(res*res)%MOD;b>>=1;}return res;
}
快速幂模板

 

 

了解了快速幂的基本思想与代码实现,我们就要来看看矩阵快速幂。其实矩阵快速幂的基本思想和普通快速幂是一样的。

对于矩阵,我相信学过线性代数的同学应该对其深恶痛绝……不要怕,我们的矩阵快速幂只涉及到矩阵的乘法,是不是很简单啊~(对于不会矩阵乘法的同学请自行百度)

对于矩阵乘法,模板如下:

 

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <string.h>
#define MOD 1000000007
typedef long long int LL;
using namespace std;
struct Matrix{int a[2][2];Matrix(){memset(a,0,sizeof(a));}Matrix operator* (const Matrix &p){Matrix res;for(int i=0;i<2;i++){for(int j=0;j<2;j++){for(int k=0;k<2;k++){res.a[i][j]+=(a[i][k]*p.a[k][j]%MOD);}res.a[i][j]%=MOD;}}return res;}
}init,unit;
矩阵乘法

 

首先来看一个例子:如果问题是求解斐波那契数列的第1000000000项对于MOD取模的值,我们应该如何去做?

从快速幂我们知道对于这个问题线性的计算是肯定超时的,所以我们依旧采用快速幂的思想。

对于斐波那契数列我们有如下规律(以下为矩阵):

f(n+1) f(n)    乘以    1     1     结果是     f(n+1)+f(n)  f(n+1)  即:f(n+2)  f(n+1)

f(n)  f(n-1)             1     0        f(n)+f(n-1)  f(n)         f(n+1)  f(n)

这是我们会惊奇的发现 当我们用斐波那契数列组成的矩阵乘以一个特定矩阵时会得到下一个斐波那契数的值。

所以不难想象,我们只要知道数列的前3项,用他们组成的矩阵乘以这个特定矩阵的k次幂就能得到任意项的斐波那契数,并且时间复杂度是O(lgn)的!

所以,到这里我们就要知道如何去找这个特定矩阵。

一般地,如果有通项公式:f(n)=a*f(n-1)+b*f(n-2)+c*f(n-3)……(这里我们以3个为例),若f(1)==p,f(2)==q,f(3)==r

我们设定一个init矩阵表示初始值:

r  0  0

q  0  0

p  0  0

一个unit矩阵表示那个特定矩阵:

a  b  c

1  0  0

0  1  0

这样,unit矩阵左乘init矩阵等于:

ap+bq+cs  0  0

            p  0  0

            q  0  0

这样我们就构造出了一个矩阵,表示出了整个数列的递推关系:

 a  b  c           f(3)  0  0       f(n+2)  0  0

(1  0  0)     的n次幂   乘以     f(2)  0  0  等于   f(n+1)  0  0

 0  1  0            f(1)  0  0           f(n)  0  0

 

当然,构造这样的矩阵的方法不一,此方法只是较为通用的方法,对于某些通项公式可以找到更简便的矩阵使得矩阵快速幂成立。

 

矩阵快速幂模板如下:

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <string.h>
#define MOD 1000000007
typedef long long int LL;
using namespace std;
struct Matrix{int a[2][2];Matrix(){memset(a,0,sizeof(a));}Matrix operator* (const Matrix &p){Matrix res;for(int i=0;i<2;i++){for(int j=0;j<2;j++){for(int k=0;k<2;k++){res.a[i][j]+=(a[i][k]*p.a[k][j]%MOD);}res.a[i][j]%=MOD;}}return res;}
}init,unit;
Matrix quick_pow(Matrix unit,Matrix init,int k){while(k){if(k&1)init=init*unit;unit=unit*unit;k>>=1;}return init;
}
void init_Matrix(){init.a[0][0]=1;init.a[0][1]=0;init.a[1][0]=0;init.a[1][1]=1;unit.a[0][0]=1;unit.a[0][1]=1;unit.a[1][0]=1;unit.a[1][1]=0;
}
矩阵快速幂

 

主函数中首先对init和unit矩阵进行初始化,然后再调用quick_pow()。

 

 

小Tips:关于如何识别矩阵快速幂的问题。

一般来说,题目中如果有”答案对于MOD取模“这句话时,并且操作次数巨大,我们就可以考虑使用快速幂或矩阵快速幂。

关于题目中有”取模“的说法时,一般来说有几种可能。一是快速幂,二是dp,三是组合数学。

另外推荐两道矩阵快速幂的题目和题解:

http://www.cnblogs.com/Torrance/p/5412802.html

http://www.cnblogs.com/Torrance/p/5410755.html

 

转载于:https://www.cnblogs.com/Torrance/p/5420957.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/470764.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

爬虫小记:利用cookies跳过登陆验证码

前言 在爬取某些网页时&#xff0c;登陆界面时经常遇到的一个坎&#xff0c;而现在大多数的网站在登陆时都会要求用户填写验证码。当然&#xff0c;我们可以设计一套机器学习的算法去破解验证码&#xff0c;然而&#xff0c;验证码的形式多种多样&#xff0c;稍微变一下&#…

Nodejs 中的包、npm 、第三方模块、 package.json 以及 cnpm

一、包与 NPM 包Nodejs 中除了它自己提供的核心模块外&#xff0c;我们可以自定义模块&#xff0c;也可以使用第三方的 模块。Nodejs 中第三方模块由包组成&#xff0c;可以通过包来对一组具有相互依赖关系的模块进行 统一管理。 完全符合 CommonJs 规范的包目录一般包含如下…

神经网络中BP(back propagation)到底在干些什么

前言 想要理解神经网络的工作原理&#xff0c;反向传播(BP)是必须搞懂的东西。BP其实并不难理解&#xff0c;说白了就是用链式法则(chain rule)算算算。本文试图以某个神经网络为例&#xff0c;尽可能直观&#xff0c;详细&#xff0c;明了地说明反向传播的整个过程。 正向传…

Nodejs 新特性 async await 的使用 以及使用 async await 处理异步

1. let 和 var 2. const定义常量 3. 模板字符串 4. 属性简写 5. 方法简写 6. 箭头函数 7. 回调函数 7. Promise 8. async 和 await

leetcode 高薪_LeetCode 第 125 号问题:验证回文串

本文首发于公众号「五分钟学算法」&#xff0c;是图解 LeetCode 系列文章之一。个人网站&#xff1a;https://www.cxyxiaowu.com题目来源于 LeetCode 第 125 号问题&#xff1a;验证回文串。这道题目是 初级程序员 在面试的时候经常遇到的一道算法题&#xff0c;而且面试官喜欢…

从拉格朗日乘子法到SVM

前言 本文主要是讲了如何构建SVM的模型&#xff0c;并利用KKT条件构造其对偶型&#xff0c;从而求解问题&#xff0c;并讲述了SVM的硬间隔&#xff0c;软间隔和核函数三个境界。主要参考了周志华的《机器学习》&#xff0c;并在其中补充了自己的想法。由于内容较多&#xff0c…

nodejs 创建一个静态资源服务器 +路由

0、补充 1、Node.js 创建的第一个应用 1、引入 http 模块 var http require("http"); 2、创建服务器 接下来我们使用 http.createServer() 方法创建服务器&#xff0c;并使用 listen 方法绑定 3000 端口。 函数通过 request, response 参数来接收和响应数据。 co…

python输出字体的大小_Python密码学编程:文件的加密与解密

在之前的章节中&#xff0c;编写的程序只能操作较少的信息&#xff0c;这些信息往往是以字符串的形式直接写在代码中的。但本章中的程序可以对整个文件进行加密和解密&#xff0c;文件的大小可以包括成千上万个字符。本章要点open()方法。读、写文件。write()、close()及read()…

电脑k歌软件_金麦客专业k歌app下载|金麦客专业k歌软件 手机安卓版v1.1.5.0 下载...

金麦客专业k歌app能够让用户通过手机直接连接电视&#xff0c;从而在安卓端实现金麦客点歌的目的&#xff0c;平台包含上万高清mv资源&#xff0c;让用户在歌唱时能够更好的代入氛围中&#xff0c;并且还能通过网络直接搜歌&#xff0c;从而在线下载播放&#xff0c;用户在演唱…

Nodejs ejs模板引擎

官方网站&#xff1a;https://www.npmjs.com/package/ejs 我们学的 EJS 是后台模板&#xff0c;可以把我们数据库和文件读取的数据显示到 Html 页面上面。它 是一个第三方模块&#xff0c;需要通过 npm 安装 npm install ejs –save 或者 cnpm install ejs --saveNodejs 中使用…

linux can总线接收数据串口打包上传_关于串口,你需要知道这些!!

嵌入式设备在电路中交换信息的时候必须通过共享一个通用的协议。现在嵌入式系统中已经定义了数百种通信协议来实现数据交换&#xff0c;一般来说可以将其分为两类&#xff1a;并行或串行。并行传输数据是指同时传输多个数据位&#xff0c;它们通常需要数据线和时钟线配合工作&a…

div里嵌套了img底部会有白块问题和图片一像素问题解决

div里嵌套了img底部会有白块 因为img默认是按基线(baseline)对齐的。对比一下图片和右边的p, q, y等字母&#xff0c;你会发现这三个字母的“小尾巴”和图片下方的空白一样高。下面这张图中的黑线就是那条基线。 解决方案&#xff1a;一&#xff1a;vertical-align: bottom&…

Nodejs 中的Get、Post

Get、Post 超文本传输协议&#xff08;HTTP&#xff09;的设计目的是保证客户端机器与服务器之间的通信。 在客户端和服务器之间进行请求-响应时&#xff0c;两种最常被用到的方法是&#xff1a;GET 和 POST。 GET - 从指定的资源请求数据。&#xff08;一般用于获取数据&#…

电脑故障扫描修复软件_电脑故障分析:电脑安装软件提示没有权限的解决方法...

我们安装软件时如果没有权限就会导致安装故障&#xff0c;最近就有用户安装软件的时候出现了无法将数值写入键software的错误提示&#xff0c;请验证您对该键拥有足够的访问权限&#xff0c;或者与您的技术支持人员联系。那么遇到这种问题该怎么办呢&#xff1f;接下来就让我们…

Nodejs 路由封装 封装一个类似 express 的路由

1、模块化的方式封装 routes.js: const http require(http); const fs require(fs); const path require(path) const url require(url) const ejs require(ejs) let getFileMime function (extname) {// 把异步读取文件方法改为同步读取文件方法let data fs.readFileSy…

天翼网关 ddns设置_19,微服务网关之Zuul

这一次给大家分享微服务网关的相关知识&#xff0c;这个也是微服务架构中&#xff0c;相当重要的组件之一&#xff0c;来&#xff0c;下面听我徐徐道来1&#xff0c;API网关概览1.1&#xff0c;现有的交互模式存在什么问题&#xff1f;目前&#xff0c;是客户端会直接跟多个微服…

MongoDB 数据库创建、删除、表(集合) 创建删除、数据的增、删、改、查

一、 连接数据库 1、连接数据库 清屏命令&#xff1a;cls 查看所有数据库列表:show dbs 二、 创建数据库、查看、删除数据库 1、使用数据库、创建数据库 use itying 如果真的想把这个数据库创建成功&#xff0c;那么必须插入一个数据。 数据库中不能直接插入数据&#xff0…

从LeetCode 210. Course Schedule II 了解拓扑排序

问题简述 给定n节课&#xff0c;每节课按0~n-1编号。 在修某些课的时候需要有其它课的基础&#xff0c;必须先上先修课。现在用pair的形式来表示要先修的课&#xff0c;比如 [ [0,1], [1,2] ] 就表示在修课程1之前必须先修课程0&#xff0c;修课程2之前必须修课程1。现在需要给…

MongoDb 大数据查询优化、 MongoDB 索引、复合索引、唯一索引、 explain 分 析查询速度

一、索引基础 索引是对数据库表中一列或多列的值进行排序的一种结构&#xff0c;可以让我们查询数据库变得 更快。 MongoDB 的索引几乎与传统的关系型数据库一模一样&#xff0c;这其中也包括一些基本的查询优化技巧。 下面是创建索引的命令&#xff1a; db.user.ensureIndex…

ipconfig不是内部或外部_晶振有什么作用,如何选择合适的晶振,为什么有时候用内部晶振?...

一、 什么是晶振晶振&#xff0c;全名叫"晶体振荡器"&#xff0c;它在电路当中起到产生振荡频率的作用&#xff0c;我们都知道&#xff0c;单片机可以看成是在时钟驱动下的时序逻辑电路&#xff0c;那么这个所需要的时钟就是晶振来产生&#xff0c;可以说它的单片机的…