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

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

最近偶然在训练赛中连续做了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;稍微变一下&#…

IOS的 testflight测试设置

管理员邀请参与者 1、登录开发者账号https://developer.apple.com/account 2、进入后&#xff0c;点击ituns connect 3、点击进入用户和职能 4、在用户栏点击添加按钮 5、输入姓名、邮件 6、勾选职能为“开发人员”&#xff0c;选择所要测试或参与研发的APP 7、不用修改&#x…

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

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

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

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

TOP 子句

TOP 子句TOP 子句用于规定要返回的记录的数目。对于拥有数千条记录的大型表来说&#xff0c;TOP 子句是非常有用的。注释&#xff1a;并非所有的数据库系统都支持 TOP 子句。SQL Server 的语法&#xff1a;SELECT TOP number|percent column_name(s)FROM table_nameMySQL 和 Or…

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()…

个人工作总结7

时间关系&#xff0c;只能等到编完了程序再做工作总结了&#xff0c;今天是第七天: 一、昨天干了什么&#xff1f; 服务器配置了一大圈&#xff0c;尝试了N1种办法&#xff0c;到最后也没有成功&#xff0c;但好像只差一点点&#xff0c;打算明天上移动应用开发咨询一下老师。 …

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

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

python的普通方法、类方法和静态方法

前言 本文主要讲述了python类中的三类常用方法&#xff0c;普通方法、类方法和静态方法。 普通方法会将实例传入方法当中&#xff08;通常用self表示&#xff09;&#xff0c;类方法会将类传入方法当中&#xff08;通常用cls表示&#xff09;&#xff0c;静态方法中传入与类无…

局部内部类和匿名内部类的对比

创建内部类的典型的方式是在一个方法体的里面创建&#xff0c;局部内部类不能有访问说明符&#xff0c;因为它不是外围类的一部分&#xff0c;但是它可以访问当前代码块内的常量,以及此外围类的所有成员。下面的例子对局部内部类与匿名内部类的创建进行了比较。 具体代码实现&a…

Nodejs ejs模板引擎

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

py2中存储的pickle和py3中pickle无法读取的兼容性问题解决方案

问题描述 在py2.7当中&#xff0c;用以下语句将变量存储到pickle当中 with open(../dataset/m_7800/rf_preds.pickle, wb) as f:pickle.dump(rf_preds, f) 这个时候&#xff0c;用py3.6中的pickle取获取存储好的变量 with open(../dataset/m_7800/rf_preds.pickle, rb) as …

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;一般用于获取数据&#…

利用二分法解决 leetcode 378. Kth Smallest Element in a Sorted Matrix

问题简述 给定一个 nn的矩阵&#xff0c;矩阵中每行和每列的元素都按升序排列。给定一个 k(k∈[1,n2])&#xff0c; 求再整个矩阵中按从小到大排序为 k的元素。 例如:matrix = [[ 1, 5, 9],[10, 11, 13],[12, 13, 15] ], k = 8,return 13.解题思路该矩阵的行和列都是按从小…