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

最近偶然在训练赛中连续做了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

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

  1. POJ3420 Quad Tiling(模板+矩阵快速幂)

    Quad Tiling Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 4107 Accepted: 1878 Descripti ...

  2. 算法分类整理+模板②:字符串处理

    本周训练赛出了一道kmp模板题,但是由于长时间没有复习字符串处理算法,而且学习时也并没有彻底理解,只是大概明白了思路,所以导致比赛时迟迟没有做出这一题,最后现场拿出学校整理的材料现场重新学习才ac的这 ...

  3. 【ZOJ 2974】Just Pour the Water(矩阵快速幂)

    传送门:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2974 题意 给出n个杯子与初始水量同时进行操作 将其中的水同时平均 ...

  4. 矩阵模板(矩阵快速幂算法用法)

    矩阵快速幂用法 应用矩阵解线性方程组入门视频 用于计算递归的方程组等:如f(n)=f(n-1)+f(n-2)+f(n-3); 在引入矩阵快速幂之前 先引入问题: 想必大家都不陌生斐波那切数. 数字公式 ...

  5. 矩阵快速幂求斐波那契数列(初学整理)

    参考文章: http://blog.csdn.net/u013795055/article/details/38599321 http://blog.csdn.net/g_congratulation ...

  6. 杭电ACM-LCY算法进阶培训班-专题训练(矩阵快速幂)

    杭电ACM-LCY算法进阶培训班-专题训练(矩阵快速幂)[模板] 传送门 杭电ACM-LCY算法进阶培训班-专题训练(矩阵快速幂)[模板] 矩阵快速幂模板 Count Problem Descript ...

  7. 51nod 算法马拉松18 B 非010串 矩阵快速幂

    51nod 算法马拉松18 B 非010串 矩阵快速幂 非010串 基准时间限制:1 秒 空间限制:131072 KB 分值: 80 如果一个01字符串满足不存在010这样的子串,那么称它为非010串 ...

  8. 蓝桥杯 算法提高 递推求值(矩阵快速幂)详解

    传送门 问题描述 已知递推公式: F(n, 1)=F(n-1, 2) + 2F(n-3, 1) + 5, F(n, 2)=F(n-1, 1) + 3F(n-3, 1) + 2F(n-3, 2) + 3 ...

  9. POJ3070 矩阵快速幂模板

    题目:http://poj.org/problem?id=3070 矩阵快速幂模板.mod写到乘法的定义部分就行了. 别忘了 I ( ) 和 i n i t ( ) 要传引用! #include< ...

最新文章

  1. KOA 在typescript下编译找不到模板render和session错误的解决
  2. 联通和阿里云合作 试点打通全国IT系统
  3. 使用Bootstrap + Vue.js实现 添加删除数据
  4. 移动端布局 - REM方式
  5. C++中INT与BYTE相互转换
  6. 计算机专业毕业设计中期考核表,研究生中期考核表导师评语
  7. windows如何安装MySql(包含一些安装时问题的解决)
  8. mysql系统变量_MySQL系统变量
  9. PHP魔术方法和魔法变量详解
  10. 我国街景地图向何处去
  11. 容斥原理 原理及模板代码
  12. 【数理方程】傅里叶级数
  13. kengoro机器人哪儿有卖_日本东京大学创造出“骨格精奇”的机器人Kengoro 会流汗能做掌上压...
  14. 5G/NR学习笔记:3GPP 38.211- Carrier Bandwith Part, BWP-载波带宽部分
  15. 手机哔哩哔哩如何转换html5,手机b站(哔哩哔哩)账号up主头像图片如何设置?怎么保存到相册里面...
  16. 代理商模式还能走多远?
  17. 磊科路由破解登入密码的办法
  18. ubuntu 20.04中sources.list文件恢复系统默认源
  19. C++ 论公有继承时纯虚函数、虚函数、普通函数的行为表现及虚函数的重写(深度好文)
  20. css中如何控住字数,css怎么限制文本字数

热门文章

  1. 如何在我们项目中利用开源的图表(js chart)
  2. 资源共享型智能指针实现方式
  3. 简析EDMX文件的构成 - CSDL、SSDL、MSL
  4. 【Hello CSS】第六章-文档流与排版
  5. Google Go Programming In Eclipse
  6. docker 中不能用vim编辑文件
  7. 当导用模块与包的import与from的问题(模块与包的调用)
  8. linux nfs配置
  9. BackGroundWorker用法
  10. Spring boot + mybatis plus 快速构建项目,生成基本业务操作代码。