矩阵乘法优化线性递推

矩阵乘法是线性代数中一块很重要的内容.矩阵乘法的定义很奇怪[1],但正是这种奇怪的性质,让矩阵乘法成为在除了线性代数和其衍生学科(还有诸如矩阵力学之类)外最广泛使用的关于矩阵变换的应用.(什么?FFT不属于矩阵变换吧...)

注:

[1]: 矩阵乘法有另外的很多定义,如未说明,指的是中间不带符号的矩阵乘法,即一般矩阵乘积.另有 标量乘积(即所有数乘上一个固定的数),阿达马乘积等,没有那么诡异,但是在大多数问题的用途上也不大.

你不会矩阵乘法?没关系,下一篇会写到的

矩阵乘法的本质

矩阵乘法的本质是线性组合.

一个线性组合是像这样的:

$c=a_1b_1 + a_2b_2 + ... + a_nb_n$

其中$a_n$这个数列是一个常量,则乘c是数列b的一个线性组合.同理对于a.

So, 如何应用到线性递推中?

让我们来看看最经典的题目,求斐波那契数列.

当你们刚学递归的时候,Fib的题目是这样的:

求$Fib(n)$,其中$Fib(n)=Fib(n-1)+Fib(n-2)$,$Fib(0)=Fib(1)=1$,$n\le 30$

你的程序大约会是这样的:

int fib(int n){
  if(n==0||n==1) return 1;
  return fib(n-1)+fib(n-2);
}你大概注意到了,这样写的效率很低,在n不大时就崩溃了.(n=30还是可以承受的.)事实上,这个时间是以指数级别增长的.

然后你们学习了记忆化搜索(其实这是一个非常好的思想,几乎是递推和动规生命的早期).这时你们的题目会是这样的:

求$Fib(n) \mod 10^9+7$,其中$Fib(n)=Fib(n-1)+Fib(n-2)$,$Fib(0)=Fib(1)=1$,$n\le 100000$

你的程序会是这样的:

int fibb[100010];
int fib(int n){//不严密.可能(几乎一定)会爆栈
  if(fibb[n]!=0){
    return fibb[n];
  }
  if(n==0||n==1) return (fibb[n]=1);
  return (fibb[n]=(fib(n-1)+fib(n-2))%1000000007);
}

相比起纯粹递归来说,这是非常好的算法.

当你们学习了递推后,程序变得快而简洁:

#include <cstdio>
int n,i,f[10000000];//大概可以处理一千万的数据.
int main(){//本文给出的第一个完整程序.
  scanf("%d",&n);
  f[0]=f[1]=1;
  for(i=2;i<=n;++i){
    f[i]=(f[i-1]+f[i-2])%1000000007;
  }
  printf("%d",f[n]);
  return 0;
}

你又知道了滚动数组.空间已经不是问题.

#include <cstdio>
int n,i,a,b,c;
int main(){
  scanf("%d",&n);
  a=b=1;
  for(i=2;i<=n;++i){
    c=(a+b)%1000000007;
    a=b;
    b=c;
  }
  printf("%d",b);
  return 0;
}

这是最优算法了么?

看起来是的,但其实这只是线性递推的初步.

线性递推是什么呢?

时间: 2024-12-21 22:47:02

矩阵乘法优化线性递推的相关文章

多校第九场:贪心+矩阵快速幂中间优化+线性递推&amp;线段树递推

HDU 4968 Improving the GPA 思路:贪心的搞吧!比赛的时候想了好久,然后才发现了点规律,然后乱搞1A. 因为贪心嘛!大的情况就是刚开始每个人的分数都是最大的最小值,即绩点4.0的最低分数85,然后最后一个数设为剩余的分数,然后如果小于60就从第一个分数补到这个分数来,然后最后一个分数还小于60,那就用第二个补--依次往下搞,那时我也不知道这样就搞出答案了,我还没证明这个对不对呢,哈哈. 小的情况:小的情况就是先假设每个人都是绩点最小的最大分数,即绩点2.0的最大分数69,

HDU 5863 cjj&#39;s string game ( 16年多校10 G 题、矩阵快速幂优化线性递推DP )

题目链接 题意 : 有种不同的字符,每种字符有无限个,要求用这k种字符构造两个长度为n的字符串a和b,使得a串和b串的最长公共部分长度恰为m,问方案数 分析 : 直觉是DP 不过当时看到 n 很大.但是 m 很小的时候 发现此题DP并不合适.于是想可能是某种组合数学的问题可以直接公式算 看到题解的我.恍然大悟.对于这种数据.可以考虑一下矩阵快速幂优化的DP 首先要想到线性递推的 DP 式子 最直观的想法就是 dp[i][j] = 到第 i 个位置为止.前面最长匹配长度为 j 的方案数 但是如果仔

矩阵快速幂优化线性递推

我们熟知的斐波那契数列递推公式是: \(f(n)=f(n-1)+f(n-2)\) 假设我们需要求斐波那契数列的第n项,当n非常大(如n=1e9)的时候,递推肯定超时.我们不妨设: \(\binom{f_{n}}{f_{n-1}}=\begin{pmatrix}a & b\\ c & d\end{pmatrix}\binom{f_{n-1}}{f_{n-2}}\) 将等式右边乘开,得到: \(\binom{af_{n-1}+bf_{n-2}}{cf_{n-1}+df_{n-2}}\) 要使其

矩阵乘法来加速递推式计算

Codevs1281: 给你6个数,m, a, c, x0, n, g Xn+1 = ( aXn + c ) mod m,求Xn 计算递推式,运用矩阵来进行计算加速 然后注意用类似快速幂的方法写一个快速加,避免溢出 怎么把式子化成矩阵,日后再补 1 #include<cstdio> 2 long long mod,a,c,x0,n,g; 3 struct Mat 4 { 5 long long m[2][2]; 6 }base,X0; 7 long long quick_add(long lo

特征多项式优化线性递推

#include <cstdio> #define EXint __uint128_t EXint n,k,p,tmp[3001],ans; inline EXint READ(){ char ch=getchar();EXint ret=0; while (ch<'0'||ch>'9') ch=getchar(); while (ch>='0'&&ch<='9'){ret*=10;ret+=ch-'0';ch=getchar();} return(re

利用Cayley-Hamilton theorem 优化矩阵线性递推

平时有关线性递推的题,很多都可以利用矩阵乘法来解k决. 时间复杂度一般是O(K3logn)因此对矩阵的规模限制比较大. 下面介绍一种利用利用Cayley-Hamilton theorem加速矩阵乘法的方法. Cayley-Hamilton theorem: 记矩阵A的特征多项式为f(x). 则有f(A)=0. 证明可以看 维基百科 https://en.wikipedia.org/wiki/Cayley–Hamilton_theorem#A_direct_algebraic_proof 另外我在

用矩阵乘法优化递推

(有关矩阵乘法的基本规则请自行搜索) 引例:求斐波那契数列的第 n 项 mod 1000000007 的值,n <= 1018. 分析:斐波那契数列的递推式为 f(n) = f(n-1)+f(n-2),直接循环求出 f(n) 的时间复杂度是 O(n),对于题目中的数据范围显然无法承受.很明显我们需要对数级别的算法. 由于 f(n) = 1*f(n-1) + 1*f(n-2) 这样的形式很类似于矩阵的乘法,所以我们可以先把这个问题复杂化一下,将递推求解 f(n) 与 f(n-1) 的过程看作是某两

BZOJ 4204 取球游戏 循环矩阵优化期望递推

题意:链接 方法:循环矩阵优化期望递推. 解析: 这题递推没啥,主要是循环矩阵优化 我们发现,如果直接上矩阵优化的话是n^3log,所以铁定是过不了了的,然后再观察一下这道题我们要求幂的矩阵,发现他是这种形式 1 1 0 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 1 1 1 0 0 0 1 每一行都是上一行向右窜了一位 所以我们可以用一个一维数组代表这个循环矩阵 并且循环矩阵求和,乘积还是循环矩阵 所以我们就可以用循环矩阵来优化掉一个n 复杂度即变为了n^2log 可过. 代码

矩阵乘法优化dp

前几天学姐说要给我们考矩乘dp和期望dp...其实我们都(也可能只有我)不会. 那只能现学了,然而学了一天突然通知不考了qwq 矩阵乘法 A矩阵为m*k,B矩阵为k*n,两矩阵相乘则得C矩阵为m*n; for (int i=1;i<=M;++i) for (int j=1;j<=N;++j) for (int k=1;k<=K;++k) c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j])%mod; 矩阵乘法模板  时间复杂度为$O(N^3)$,数学一本通上