矩阵快速幂小结

矩阵

并不想扯什么高端线代的内容因为我也不会

定义

由$n \times m$个数$a_{ij}$排成的$n$行$m$列的数表称为$n$行$m$列的矩阵,简称$n \times m$矩阵。

$$
A =
\begin{bmatrix}
a_{11} & a_{12} & \dots a_{1m} \\
a_{21}, & \dots & \dots \\
a_{31}, & \dots & \dots \\
a_{41} & \dots & a_{nm}
\end{bmatrix}
$$

运算

这里只讲加法减法和乘法,其他的例如矩阵求逆等与本文内容出入较大,有兴趣的可以自己学习

加法

注意,只有行列均相同的矩阵才有加法!

运算也比较简单,把对应位置的数相加得到一个新的矩阵,即为答案

例如

$$
\begin{bmatrix} 1 & 1 & 2 \\ 1 & 0 & 1 \end{bmatrix}
+
\begin{bmatrix} 2 & 3 & 3 \\ 3 & 3 & 2 \end{bmatrix}
=
\begin{bmatrix} 3 & 4 & 5 \\ 4 & 3 & 3 \end{bmatrix}
$$

加法满足以下运算律

$A + B = B + A$

$(A + B) + C = A + (B + C)$

减法

与加法同理。

乘法

这才是重点!!

两个矩阵能进行乘法的前提条件是:一个矩阵的行数等于另一个矩阵的列数

形式化的来说,若$A$是$i \times k$的矩阵,那么$B$必须是$k \times j$的矩阵!

他们相乘得到的$C$是$i \times j$的矩阵

其中$C_{ij} = \sum_{i = 1}^n A_{ik} * B_{kj}$

比如

$$
\begin{bmatrix} 1 & 2\\ 2 & 3 \end{bmatrix}
\times
\begin{bmatrix} 2 & 4 & 5 \\ 3 & 4 & 3 \end{bmatrix}
=
\begin{bmatrix} 8 & 12 & 11 \\ 13 & 20 & 19 \end{bmatrix}
$$

乘法满足结合律,左分配律,右分配律,即

$(A \times B) \times C = A \times (B \times C)$

$(A + B) \times C = A \times C + B \times C$

$C(A + B) = C \times A + C \times B$

千万注意!矩阵乘法不满足交换律!(很多情况下交换之后都不能相乘)

矩阵快速幂

因为矩阵有结合律,因此我们可以把整数的快速幂推广的矩阵上面

题目链接

同样是利用二进制倍增的思想,不难得到以下代码

其中的base,代表的是单位矩阵,也就是除了对角线全为$1$,其他位置都为$0$的矩阵,可以证明任意矩阵乘单位矩阵都等于自身

显然矩阵快速幂的复杂度为$O(n^3 log k)$

#include<cstdio>
#define LL long long
using namespace std;
const int mod = 1e9 + 7;
int N;
LL K;
struct Matrix {
    int m[101][101];
    Matrix operator * (const Matrix &rhs) const {
        Matrix ans = {};
        for(int k = 1; k <= N; k++)
            for(int i = 1; i <= N; i++)
                for(int j = 1; j <= N; j++)
                    (ans.m[i][j] += 1ll * m[i][k] * rhs.m[k][j] % mod) %= mod;
        return ans;
    }
};
Matrix fastpow(Matrix a, LL p) {
    Matrix base;
    for(int i = 1; i <= N; i++) base.m[i][i] = 1;//构造单位矩阵
    while(p) {
        if(p & 1) base = base * a;
        a = a * a; p >>= 1;
    }
    return base;
}
int main() {
    scanf("%d %lld", &N, &K);
    Matrix a;
    for(int i = 1; i <= N; i++)
        for(int j = 1; j <= N; j++)
            scanf("%d", &a.m[i][j]);
    a = fastpow(a, K);
    for(int i = 1; i <= N; i++, puts(""))
        for(int j = 1; j <= N; j++)
            printf("%d ", a.m[i][j]);

    return 0;
}

应用

矩阵快速幂最常见的应用就是优化递推啦

还是从最常见的斐波那契数列说起吧。

众周所知,斐波那契数列的递推公式为$$f_{n} = f_{n - 1} + f_{n - 2}, f_1 = 1, f_2 = 1$$

一般来说,这种看起来长得很萌简单,只与自身的函数值有关(可能带几个常数)的式子,一般都可以用矩阵快速幂来加速。

当然,如果你想找刺激,可以学一下这玩意儿

矩阵快速幂具体是怎么加速递推的呢?

首先我们把斐波那契数列写成矩阵的形式,因为$f_n$的取值与$f_{n - 1}, f_{n - 2}$这两项有关,因此我们需要同时保留这两项的值,我们不难得到一个$2 \times 1$的矩阵

$$
\begin{bmatrix}
f_{n} \\
f_{n - 1}
\end{bmatrix}
$$

现在我们要进行递推,也就是得到这样一个矩阵

$$
\begin{bmatrix}
f_{n + 1} \\
f_{n}
\end{bmatrix}
$$

展开

$$
\begin{bmatrix}
f_{n} + f_{n - 1} \\
f_{n}
\end{bmatrix}
$$

观察一下,上面的一项需要用到$f_{n}$和$f_{n - 1}$,下面的一项只需要用到$f_n$

同时结合上面的矩阵乘法的定义,我们不难得到一个转移矩阵

$$
\begin{bmatrix} 1 & 1 \\ 1 & 0 \\ \end{bmatrix}
\begin{bmatrix} f_{n} \\ f_{n - 1}\\ \end{bmatrix}
=
\begin{bmatrix} f_{n} + f_{n - 1} \\ f_{n}\\ \end{bmatrix}
$$

这样我们乘一次即可递推到下一项。

但是这样好像并没有什么卵用啊,复杂度上还多了个矩阵相乘

嘿嘿

不要忘了,我们前面可以讲过矩阵有结合律的!

这样的话我们只需要把转移矩阵自乘$n - 1$次,然后再与初始矩阵相乘,就能得到答案矩阵啦!

题目链接

// luogu-judger-enable-o2
#include<cstdio>
#include<cstring>
#define LL long long
using namespace std;
const int mod = 1e9 + 7;
LL K;
struct Matrix {
    int m[101][101], N;
    Matrix() {
        memset(m, 0, sizeof(m));
        N = 2;
    }
    Matrix operator * (const Matrix &rhs) const {
        Matrix ans;
        for(int k = 1; k <= N; k++)
            for(int i = 1; i <= N; i++)
                for(int j = 1; j <= N; j++)
                    (ans.m[i][j] += 1ll * m[i][k] * rhs.m[k][j] % mod) %= mod;
        return ans;
    }
};
Matrix fastpow(Matrix a, LL p) {
    Matrix base;
    for(int i = 1; i <= base.N; i++) base.m[i][i] = 1;//鏋勯€犲崟浣嶇煩闃?
    while(p) {
        if(p & 1) base = base * a;
        a = a * a; p >>= 1;
    }
    return base;
}
int main() {
    scanf("%lld", &K);
    Matrix a;
    a.m[1][1] = 1; a.m[1][2] = 1;
    a.m[2][1] = 1; a.m[2][2] = 0;
    a = fastpow(a, K - 1);
    printf("%d", a.m[1][1]);
    return 0;
}

代码

原文地址:https://www.cnblogs.com/zwfymqz/p/9642901.html

时间: 2024-10-07 22:17:52

矩阵快速幂小结的相关文章

矩阵快速幂的一份小结

矩阵真是个好东西!虽然矩乘的复杂度有点难看... ... 这几天也做了不少矩阵题目,还是有几道好题目的.不过我打算从入门开始. 矩阵乘法:A[i][k]*B[k][j]=C[i][j];(A的第i行的每项依次乘以B的第j列的每项的和) 很显然这是一个n^3的算法,还是比较难看的. 代码就差不多是这样了. struct Matrix{int T[51][51];}; Matrix Mul(Matrix a,Matrix b,int I,int K,int J) { Matrix S=S0; for

【做题】SRM701 Div1 Hard - FibonacciStringSum——数学和式&矩阵快速幂

原文链接 https://www.cnblogs.com/cly-none/p/SRM701Div1C.html 题意:定义"Fibonacci string"为没有连续1的01串.现在,给出\(a,b\),定义一个"Fibonacci string"的权值为\(x^a y^b\),其中\(x\)为0的个数,\(y\)为1的个数. 要求对所有长度为\(n\)的"Fibonacci string"的权值求和,对\(10^9 + 7\)取模. \(n

矩阵快速幂刷题系列

来源自http://blog.csdn.net/chenguolinblog/article/details/10309423 hdu 1575 Tr A Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 5587    Accepted Submission(s): 4200 Problem Description A为一个方阵,则Tr

HDU 1757 A Simple Math Problem (矩阵快速幂)

[题目链接]:click here~~ [题目大意]: If x < 10 f(x) = x. If x >= 10 f(x) = a0 * f(x-1) + a1 * f(x-2) + a2 * f(x-3) + -- + a9 * f(x-10); 问f(k)%m的值. [思路]:矩阵快速幂,具体思路看代码吧,注意一些细节. 代码: #include<bits/stdc++.h> using namespace std; typedef long long LL; const

Codeforces Round #291 (Div. 2) E - Darth Vader and Tree (DP+矩阵快速幂)

这题想了好长时间,果断没思路..于是搜了一下题解.一看题解上的"快速幂"这俩字,不对..这仨字..犹如醍醐灌顶啊...因为x的范围是10^9,所以当时想的时候果断把dp递推这一方法抛弃了.我怎么就没想到矩阵快速幂呢.......还是太弱了..sad..100*100*100*log(10^9)的复杂度刚刚好. 于是,想到了矩阵快速幂后,一切就变得简单了.就可以把距离<=x的所有距离的点数都通过DP推出来,然后一个快速幂就解决了. 首先DP递推式很容易想到.递推代码如下: for(

POJ 3233 - Matrix Power Series ( 矩阵快速幂 + 二分)

POJ 3233 - Matrix Power Series ( 矩阵快速幂 + 二分) #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long LL; #define MAX_SIZE 30 #define CLR( a, b ) memset( a, b, sizeof(a) ) int MOD = 0; int n, k; st

HDU 4990 Reading comprehension(找规律+矩阵快速幂)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4990 Problem Description Read the program below carefully then answer the question. #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include<iostream> #include

hdu 6198(矩阵快速幂)

number number number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 175    Accepted Submission(s): 119 暴力发现当4 12 33 88 232 和斐波那契数列对比  答案为 第2*k+3个数减1 直接用矩阵快速幂求的F[2*k+3]  然后减1 A=1,B=0; 然后矩阵快速幂2*k

矩阵快速幂 模板与简单讲解

模板 快速幂模板 1 void solve(matrix t,long long o) 2 { 3 matrix e; 4 5 memset(e.a,0,sizeof(e.a)); 6 7 for (int i = 0;i < d;i++) 8 e.a[i][i] = 1; 9 10 while (o) 11 { 12 if (o & 1) 13 { 14 e = mul(e,t); 15 } 16 17 o >>= 1; 18 19 t = mul(t,t); 20 } 21