矩阵乘法&&矩阵快速幂&&最基本的矩阵模型——斐波那契数列

矩阵,一个神奇又令人崩溃的东西,常常用来优化序列递推

在百度百科中,矩阵的定义:

在数学中,矩阵(Matrix)是一个按照长方阵列排列的复数或实数集合 ,最早来自于方程组的系数及常数所构成的方阵。这一概念由19世纪英国数学家凯利首先提出。

好,很高深对吧。那我们就更加直接地理解一下矩阵的实质:二维数组

好了这个SB都会,就不解释了

同二维数组一样,矩阵是一个‘纵横排列的二维数据表格‘,它一般是一个n*m的二维数组,其中n*m表示它有n行m列

每一位上的数可以用下标i,j来表示,形如这样一个矩阵:

这里我们就可以用B[1][2]来表示8这个元素

矩阵有加/减/乘法(有没有除法我不知道),其中加减法的限制比较大,当且仅当两个矩阵的行列数都相等时才能进行加减

加减的操作也很简单,只需要按位加减即可

这些都是次要的,最主要的其实是矩阵乘法

我们定义矩阵乘法:设A为mp的矩阵,B为pn的矩阵,那么称m*n的矩阵C为矩阵A与B的乘积,记作C=AB,其中矩阵C中的第i行第j列元素可以表示为:

这样我们就很轻松的得到了一个O(n^3)的矩阵乘法,虽然还有更快的,但一般来说已经足够

矩阵乘法有以下几条重要性质:

  1. 矩阵乘法满足集合律,即(AB)C=A(BC)
  2. 矩阵乘法满足分配律,即(A+B)C=AC+BC
  3. 矩阵乘法一般不满足交换律

以上第三条就告诉我们,平时写两个数相乘的时候可以为所欲为,但是矩阵就完全不同了,AB!=BA

很简单,结合矩阵乘法来理解下。

换句更简单的,甚至交换后这两个矩阵都无法相乘,因为他们的列数可能就不相等了

然后我们又由于第一条可以得出矩阵快速幂的算法

首先矩阵幂只有方阵(即行数等于列数的矩阵)才可以做,要不然到后面都乘不了了(还是因为列数不相等了)

这个也很简单,我们只需要把一般的快速幂乘法部分改成矩阵乘法即可

还是一句话:不要乘反了!

对了,还要引出一个叫单位矩阵的东西,这个就好比一般乘法中的单位1一样。任何一个矩阵乘上单位矩阵都得到原来这个矩阵

单位矩阵为:

就是一个矩阵对角线上都是1

自己动手推一下就可以更深刻地理解一下了

然后我们就引出我们讨论的问题:斐波那契数列的矩阵优化

例题:Luogu P1962 斐波那契数列,求斐波那契数列的第n项%一个数的值

我们可以利用矩阵在线性代数和方程的作用在解决这个问题

我们考虑一个矩阵:

然后我们用一个列向量(就是列数为1的矩阵)来表示一下当前状态下斐波那契数列的值,由于斐波那契数列只要用到前两项,因此我们可以设:

然后我们让这两个矩阵相乘,得到新的矩阵:

上面的这一项不就是斐波那契的递推式了吗?而且下面的这一项刚好可以为下一次做准备

因此我们只需要把原来的[1,1]列向量乘斐波那契的递推矩阵(n-2)次即可(注意前面的两项就是初始值)

但是如果就是这样的话就太慢了,因此我们又联想到矩阵乘法的结合律

即直接先求出斐波那契矩阵的(n-2)次,然后再与[1,1]的列向量相乘即可

再简化后就是斐波那契矩阵的(n-2)次的[1][1]与[1][2]上值的和

这样就完成了矩阵的第一步也是最简单,最基础的一步

注意矩阵一般的写法还是写成结构体比较好

由于这里的矩阵大小都是确定的,就没有在矩阵中记录行列数了,一般情况下都是以记录为主

好了接下来给出CODE

#include<cstdio>
using namespace std;
typedef long long LL;
const LL N=3,mod=1000000007;
LL F[N],ans[N];
struct Matrix
{
    LL a[N][N];
    inline void init(void)
    {
        a[1][1]=a[2][2]=1;
        a[1][2]=a[2][1]=0;
    }
    inline void Fb_init(void)
    {
        a[1][1]=a[1][2]=a[2][1]=1;
        a[2][2]=0;
    }
};
inline Matrix mul(Matrix A,Matrix B)
{
    register int i,j,k;
    Matrix C;
    for (i=1;i<N;++i)
    for (j=1;j<N;++j)
    for (C.a[i][j]=0,k=1;k<N;++k)
    C.a[i][j]=(C.a[i][j]+A.a[i][k]*B.a[k][j])%mod;
    return C;
}
inline Matrix quick_pow(Matrix A,LL p)
{
    Matrix B; B.init();
    while (p)
    {
        if (p%2) B=mul(B,A);
        A=mul(A,A); p/=2;
    }
    return B;
}
int main()
{
    register int i,j;
    LL n; scanf("%lld",&n);
    if (n<=2) { puts("1"); return 0; }
    n-=2; F[1]=F[2]=1;
    Matrix A; A.Fb_init();
    A=quick_pow(A,n);
    printf("%lld",(A.a[1][1]+A.a[1][2])%mod);
    return 0;
}

(以上的一部分图片来自百度百科,一部分来自于Luogu憧憬未来 dalao)的题解

原文地址:https://www.cnblogs.com/cjjsb/p/9042781.html

时间: 2024-10-29 10:46:13

矩阵乘法&&矩阵快速幂&&最基本的矩阵模型——斐波那契数列的相关文章

【矩阵乘法】【快速幂】【递推】斐波那契数列&amp;&amp;矩乘优化递推模板

题目大意: 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,则有: F[n+1] F[n] = An * F[1] F[0] = An * 1 0 然后可以快速幂 #include<cstdio> #include<vector> using namespace std; typedef vector<int> vec; typed

计算 num 的 n 次幂、n 的阶乘、斐波那契数列、字符串的字节长度、去除字符串中的重复字符

1 //计算 num 的 n 次幂 2 function numPow(num, n) { 3 if (n == 1) { 4 return num; 5 } 6 return num * numPow(num, n - 1); 7 } 8 9 //计算 n 的阶乘 10 function nFactorial(n) { 11 if (n == 1) { 12 return 1; 13 } 14 return n * nFactorial(n - 1); 15 } 16 17 //斐波那契数列,

【模板】【矩阵快速幂】求第n项斐波那契

注意a数组初始化,调用Pow(a,n,w),n是第几项,求斐波那契中w默认为2 ll tmp[2][2],res[2][2]; void multi(ll a[][2],ll b[][2],int n) { memset(tmp,0,sizeof(tmp)); for(ll i=0;i<n;i++) { for(ll j=0;j<n;j++) { for(ll k=0;k<n;k++) { tmp[i][j]+=(a[i][k]*b[k][j])%p; } tmp[i][j]=tmp[i

快速求斐波那契数列(矩阵乘法+快速幂)

斐波那契数列 给你一个n:f(n)=f(n-1)+f(n-2) 请求出 f(f(n)),由于结果很大请 对答案 mod 10^9+7; 1<=n<=10^100; 用矩阵乘法+快速幂求斐波那契数列是经典应用: 矩阵公式 C i j=C i k *C k j; 根据递推式 构造2*2矩阵: 原始矩阵 1 0 0 1 矩阵 2 1 1 1 0 原始矩阵与矩阵 2相乘达到转化状态效果: 对矩阵二进行快速幂 乘法:达到快速转化矩阵的效果: 即使达到快速转化状态:那么大的数据范围也很难求解: 高精?这有

矩阵乘法快速幂 codevs 1574 广义斐波那契数列

codevs 1574 广义斐波那契数列 时间限制: 1 s 空间限制: 256000 KB 题目等级 : 钻石 Diamond 题目描述 Description 广义的斐波那契数列是指形如an=p*an-1+q*an-2的数列.今给定数列的两系数p和q,以及数列的最前两项a1和a2,另给出两个整数n和m,试求数列的第n项an除以m的余数. 输入描述 Input Description 输入包含一行6个整数.依次是p,q,a1,a2,n,m,其中在p,q,a1,a2整数范围内,n和m在长整数范围

【矩阵快速幂】HDU 4549 : M斐波那契数列(矩阵嵌套)

[题目链接]click here~~ [题目大意] M斐波那契数列F[n]是一种整数数列,它的定义如下: F[0] = a F[1] = b F[n] = F[n-1] * F[n-2] ( n > 1 ) 现在给出a, b, n,你能求出F[n]的值吗?对每组测试数据请输出一个整数F[n],由于F[n]可能很大,你只需输出F[n]对1000000007取模后的值即可,每组数据输出一行. [Source] :2013金山西山居创意游戏程序挑战赛――初赛(2) [解题思路] 这个题稍微有点难度,就

poj 3070 Fibonacci (矩阵快速幂求斐波那契数列的第n项)

题意就是用矩阵乘法来求斐波那契数列的第n项的后四位数.如果后四位全为0,则输出0,否则 输出后四位去掉前导0,也...就...是...说...输出Fn%10000. 题目说的如此清楚..我居然还在%和/来找后四位还判断是不是全为0还输出时判断是否为0然后 去掉前导0.o(╯□╰)o 还有矩阵快速幂的幂是0时要特判. P.S:今天下午就想好今天学一下矩阵乘法方面的知识,这题是我的第一道正式接触矩阵乘法的题,欧耶! #include<cstdio> #include<iostream>

(矩阵快速幂)51NOD 1242斐波那契数列的第N项

斐波那契数列的定义如下: F(0) = 0 F(1) = 1 F(n) = F(n - 1) + F(n - 2) (n >= 2) (1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, ...) 给出n,求F(n),由于结果很大,输出F(n) % 1000000009的结果即可. 输入 输入1个数n(1 <= n <= 10^18). 输出 输出F(n) % 1000000009的结果. 输入样例 11 输出样例 89解:由于斐波那

HDU 4549 M斐波那契数列(矩阵快速幂)

Problem Description M斐波那契数列F[n]是一种整数数列,它的定义如下: F[0] = a F[1] = b F[n] = F[n-1] * F[n-2] ( n > 1 ) 现在给出a, b, n,你能求出F[n]的值吗? Input 输入包含多组测试数据: 每组数据占一行,包含3个整数a, b, n( 0 <= a, b, n <= 10^9 ) Output 对每组测试数据请输出一个整数F[n],由于F[n]可能很大,你只需输出F[n]对1000000007取模