浅谈矩阵加速——以时间复杂度为O(log n)的算法实现裴波那契数列第n项及前n之和使用矩阵加速法的优化求法
首先请连矩阵乘法乘法都还没有了解的同学简单看一下这篇博客:
https://blog.csdn.net/weixin_44049566/article/details/88945949
首先直接暴力求使用O(n)的时间复杂度肯定是不行的,所以我们应该使用更优的时间复杂度。
设f(n)为裴波那契数列第n项。让我们来构造两个矩阵:
和.
现在我们不妨将两个矩阵相乘,化简过后可以得到:,也就是.
如果再将得到的新矩阵乘以,便可以得到。
也就是我们想得到第n项,就可以这么实现:,也就是。
看到幂我们就可以想到快速幂,所以最后程序的时间复杂度便是O(log n)。
代码
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define N 10
#define LL long long
int n,mod;
struct Matrix {
LL n,m,c[N][N];
Matrix() { memset(c,0,sizeof(c)); };
void _read() {
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%lld",&c[i][j]);
}
Matrix operator * (const Matrix& a) {
Matrix r;
r.n=n;r.m=a.m;
for(int i=1;i<=r.n;i++)
for(int j=1;j<=r.m;j++)
for(int k=1;k<=m;k++)
r.c[i][j]= (r.c[i][j]+ (c[i][k] * a.c[k][j])%mod)%mod;
return r;
}
void _print() {
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
if(j!=1) cout<<" ";
cout<<c[i][j];
}
if(i!=n) puts("");
}
}
Matrix _power(int indexx) {
Matrix tmp,sum;tmp._pre1();sum._pre1();
while(indexx>0) {
if(indexx&1) sum=sum*tmp;
tmp=tmp*tmp;
indexx/=2;
}
return sum;
}
void _pre1() {
n=m=2;
c[1][1]=0;
c[1][2]=c[2][1]=c[2][2]=1;
}
void _pre2() {
n=1,m=2;
c[1][1]=c[1][2]=1;
}
}T,ans;
int main() {
cin>>n>>mod;
ans._pre2();
T._pre1();
if(n<=2) { cout<<1; return 0; }
T=T._power(n-3);
ans=ans*T;
cout<<ans.c[1][2];
}
那么前n项之和呢?
这里我们可以这么构造两个矩阵:(S(n)为前n项之和)
和将两个矩阵相乘,剩下的留给读者思考。
这里给出代码:
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define N 10
#define LL long long
int n,mod;
struct Matrix {
LL n,m,c[N][N];
Matrix() { memset(c,0,sizeof(c)); };
void _read() {
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%lld",&c[i][j]);
}
Matrix operator * (const Matrix& a) {
Matrix r;
r.n=n;r.m=a.m;
for(int i=1;i<=r.n;i++)
for(int j=1;j<=r.m;j++)
for(int k=1;k<=m;k++)
r.c[i][j]= (r.c[i][j]+ (c[i][k] * a.c[k][j])%mod)%mod;
return r;
}
void _print() {
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
if(j!=1) cout<<" ";
cout<<c[i][j];
}
if(i!=n) puts("");
}
}
Matrix _power(int indexx) {
Matrix tmp,sum;tmp._pre1();sum._pre1();
while(indexx>0) {
if(indexx&1) sum=sum*tmp;
tmp=tmp*tmp;
indexx/=2;
}
return sum;
}
void _pre1() {
n=m=3;
c[3][2]=c[3][3]=c[2][3]=c[1][1]=c[2][1]=c[3][1]=1;
}
void _pre2() {
n=1,m=3;
c[1][1]=2;c[1][3]=c[1][2]=1;
}
}T,ans;
int main() {
cin>>n>>mod;
if(n==2) return printf("%d",2%mod),0;
if(n==1) return printf("%d",1%mod),0;
ans._pre2();
T._pre1();
if(n<=2) { cout<<1; return 0; }
T=T._power(n-3);
ans=ans*T;
cout<<ans.c[1][1];
}
浅谈矩阵加速——以时间复杂度为O(log n)的算法实现裴波那契数列第n项及前n之和使用矩阵加速法的优化求法的更多相关文章
- [矩阵乘法]裴波拉契数列II
[ 矩 阵 乘 法 ] 裴 波 拉 契 数 列 I I [矩阵乘法]裴波拉契数列II [矩阵乘法]裴波拉契数列II Description 形如 1 1 2 3 5 8 13 21 34 55 89 ...
- [矩阵乘法]裴波拉契数列III
[ 矩 阵 乘 法 ] 裴 波 拉 契 数 列 I I I [矩阵乘法]裴波拉契数列III [矩阵乘法]裴波拉契数列III Description 求数列f[n]=f[n-1]+f[n-2]+1的第N ...
- 斐波那契数列第N项f(N)[矩阵快速幂]
矩阵快速幂 定义矩阵A(m*n),B(p*q),A*B有意义当且仅当n=p.即A的列数等于B的行数. 且C=A*B,C(m*q). 例如: 进入正题,由于现在全国卷高考不考矩阵,也没多大了解.因为遇到 ...
- 51nod--1242 斐波那契数列第N项 (矩阵乘法优化)
题目: 1242 斐波那契数列的第N项 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题 收藏 关注 斐波那契数列的定义如下: F(0) = 0 F(1) = 1 F(n) ...
- 斐波那契数列F(n)【n超大时的(矩阵加速运算) 模板】
hihocoder #1143 : 骨牌覆盖问题·一 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 骨牌,一种古老的玩具.今天我们要研究的是骨牌的覆盖问题: 我们有一个 ...
- poj3070 求斐波那契数列第n项 ——矩阵快速幂
题目:http://poj.org/problem?id=3070 用矩阵快速幂加速递推. 代码如下: #include<iostream> #include<cstdio> ...
- 【矩阵乘法】【快速幂】【递推】斐波那契数列&&矩乘优化递推模板
题目大意: F[0]=0 F[1]=1 F[n+2]=F[n+1]+F[n] 求F[n] mod 104. F[n+2] F[n+1] = 1 1 1 0 * F[n+1] F[n] 记这个矩阵为A, ...
- HDU4549 M斐波那契数列 矩阵快速幂+欧拉函数+欧拉定理
M斐波那契数列 Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)Total Sub ...
- HDU----(4549)M斐波那契数列(小费马引理+快速矩阵幂)
M斐波那契数列 Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)Total Sub ...
随机推荐
- Linux--Linux的网络--05
一层: HUB --- 集线器 总线型结构,使用泛洪方式 二层: 在早期,pc通信只需要MAC地址进行数据转发 网桥 --- 交换机 :维护MAC地址表 三层: 网络的增大,就需要逻辑地址(IP地址 ...
- hdu 5890 01背包 bitset
注意不能每个T都mem 不然会T #include <bits/stdc++.h> #define PI acos(-1.0) #define mem(a,b) memset((a),b, ...
- 1129. Recommendation System (25)
Recommendation system predicts the preference that a user would give to an item. Now you are asked t ...
- 使用pycharm创建git项目的过程
首先建立远程仓库,然后将远程仓库克隆到本地 然后在pycharm中以该目录创建项目(如果遇到说目录非空,不用管它,Location直接粘贴古来,不然找不到路径) 如果构建好项目说无效的SDK,那么选择 ...
- POJ 3741 Raid (平面最近点对)
$ POJ~3741~Raid $ (平面最近点对) $ solution: $ 有两种点,现在求最近的平面点对.这是一道分治板子,但是当时还是想了很久,明明知道有最近平面点对,但还是觉得有点不对劲. ...
- git详细使用教程
一:Git是什么? Git是目前世界上最先进的分布式版本控制系统. 二:SVN与Git的最主要的区别? SVN是集中式版本控制系统,版本库是集中放在中央服务器的,而干活的时候,用的都是自己的电脑,所以 ...
- codevs 2039 骑马修栅栏 USACO x
题目描述 Description Farmer John每年有很多栅栏要修理.他总是骑着马穿过每一个栅栏并修复它破损的地方. John是一个与其他农民一样懒的人.他讨厌骑马,因此从来不两次经过一个栅栏 ...
- ubantu apt-get install安装php及开展
.安装php apt-get install libapache2-mod-php5 php5 报错 E: Package 'libapache2-mod-php5' has no installat ...
- 6.20校内考试整理——大美江湖&&腐草为萤&&锦鲤抄题解
先安利一下题目作者:一扶苏一 先看第一题: 这道题就是一道简单的模拟题,只要不管一开始的位置,模拟移动与格子对应的触发事件就行了.话不多说,看代码: #include<iostream> ...
- Android 拖拽功能的使用实例
图片的拖拉功能是处理图片进一个有用且常用的功能,由于手机屏幕尺寸的限制,往往无法在手机上一次性的显示一张比较大的图片,也就是说,我们在手机上一次性只能看到图片的一部分,此时就可以使用图片的拖动功能来拖 ...