矩阵

矩阵的基本概念

矩阵的定义

  由 m×n 个数 aij 排成的 mn 列的数表称为 mn 列的矩阵,简称 m×n 矩阵。记作:

A=[a11a12a1na21a22a2nam1am2amn]

  这 m×n 个数称为矩阵 A 的元素,简称为元,数 aij 位于矩阵 A 的第 i 行第 j 列。上面的矩阵还可以简记为:A=Am×n=(aij)m×n=(aij)

几种特殊的矩阵

  1. 行数和列数都等于 n 的矩阵 A, 称为 n 阶方阵(也叫 n 阶矩阵)。

    A=(a11a12a1na21a22a2nan1an2ann)

  2. 只有一行的矩阵称为行矩阵(或行向量)。

    A=(a1,a2,,an)

  3. 只有一列的矩阵称为列矩阵(或列向量)。

    A=(a1a2an)

  4. 矩阵 AB 的行数列数分别相同,称为同型矩阵

  5. 元素全为 0 的矩阵称为零矩阵,记做 0。注意:不同阶数的零矩阵是不相同的。

    (000000000)(0,0,0)

  6. 主对角线(左上到右下)的元素都为 1,其他元素都为 0n方阵称为单位矩阵

    En=In=(100010001)

      同时单位矩阵也可以简单地记为一个对角线矩阵:En=In=diag(1,1,,1)

      对于不同矩阵他们的单位矩阵大小是不同的,对于 n×m 的矩阵,它的单位矩阵大小为 m×m ,对于 m×n 的矩阵,它的单位矩阵大小为 n×n 。也就是说单位矩阵都是正方形的,这是因为只有正方形的矩阵能保证结果和前一个矩阵形状相同

  7. 对角矩阵(diagonal matrix)是一个主对角线主)之外的元素皆为 0 的方阵。

    A=(λ1000λ2000λn)

    其中 λ1,λ2,,λn 不全为 0,也可记作:A=diag(λ1,λ2,,λn)

  8. 如果两个同型矩阵的对应元素相等,则两个矩阵相等。

线性变换矩阵

  线性变换矩阵 (matrix of a linear transformation)一种特殊矩阵。指该矩阵可以通过线性变换得到。

  n 个变量 x1,x2,,xnm 个变量 y1,y2,,ym 之间的关系式:

{y1=a11x1+a12x2++a1nxny1=a21x1+a21x2++a2nxnym=am1x1+am2x2++amnxn

  表示从变量x1,x2,,xn 到变量 y1,y2,,ym 的线性变换,其中 aij 为常数。

  我们把系数取出,写成矩阵的形式,其系数矩阵为:

A=(a11a12a1na21a22a2nam1am2amn)

  可以看出线性变换与矩阵之间存在一一对应的关系。

矩阵运算

1. 矩阵加减法

  设有两个 m×n 的矩阵 A=(aij) 和矩阵 B=(bij),那么 AB 的和记为 A+B,规定:

A±B=(a11±b11a12±b12a1n±b1na21±b21a22±b22a2n±b2nam1±bm1am2±bm2amn±bmn)

  注意:两个同型矩阵才可以做加法。

矩阵的加减法满足的运算定律

交换律 A+B=B+A

结合律 (A+B)+c=A+(B+C)

2.矩阵乘法

  设 A=(aij) 是一个 m×s 矩阵, B=(bij) 是一个 s×n 矩阵,那么 AB 的乘积 C=(cij) 是一个 m×n 矩阵,其中:

cij=ai1b1j+ai2b2j+aisbsj=k=1saikbkjA=(a11a12a13a21a22a23),B=(b11b12b21b22b31b32)C=AB(a11b11+a12b21+a13b31a11b12+a12b22+a13b32a21b11+a22b21+a23b31a21b12+a22b22+a23b32)

矩阵乘法满足的运算定律:

结合律(AB)C=A(BC)

左分配律(A+B)C=AC+BC

右分配律C(A+B)=CA+CB

数乘k(AB)=(kA)B=A(kB)

转置(AB)T=BTAT

  设 Am×n 阶矩阵(即 mn 列),第 ij 列的元素是 a(i,j),即:把 m×n 矩阵 A 的行换成同序数的列得到一个 n×m 矩阵,此矩阵叫做 A 的转置矩阵,记做 AT 。例如:

A=(120314)AT=(132104)

转置的基本性质

  1. (AT)T=A
  2. (A+B)T=AT+BT
  3. (kA)T=kAT
  4. (AB)T=BTAT

注意:矩阵乘法一般不满足交换律

矩阵乘法代码
#include<bits/stdc++.h>
const int maxn = 100 + 5;
using namespace std;
int a[maxn][maxn], b[maxn][maxn], c[maxn][maxn];
int main(){
    int m,n,k;
    scanf("%d%d%d", &m, &n, &k);
    for(int i = 1; i <= m; ++i)
        for(int j = 1; j <= n; ++j)
            scanf("%d", &a[i][j]);
    for(int i = 1; i <= n; ++i)
        for(int j = 1; j <= k; ++j)
            scanf("%d", &b[i][j]);
    for(int i = 1; i <= m; ++i)//枚举a的行数m
        for(int j = 1; j <= k; ++j)//枚举b的列数k
            for(int kk = 1; kk <= n; ++kk)//枚举a的列(b的行)
                c[i][j] += a[i][kk]*b[kk][j];
    return 0;
}

Fibonacci 数列

时间限制:1 s 内存限制:128 MB 文件:

题目描述

  斐波拉切数列,f0,f1,,fn ,满足:f0=0,f1=1,fn=fn2+fn1(n>=2) ,请求出 fn 的值,由于答案可能会很大,只需输出答案模 10000 的结果。

输入格式

  输入包含多组数据,第一行为一个正整数 T,表示有T组输入。

  每组输入为一个正整数 n ,表示求斐波拉切数列第 n 的值模 10000 的结果。

输出格式

  对每组输入输出一个答案。

样例输入

4
0
9
999999999
1000000000

样例输出

0
34
626
6875

样例解释

数据范围与提示

  对 100% 的数据满足:1T100,0n109

分析

  O(log(n)) 的递推很容想到,但 n 高达 109 显然在线性时间效率上显然会超时,构造矩阵A=[11\10],列矩阵 Bn=[fn\fn1] ,则有:

AB1=[1110][f1f0]=[f0+f1f1]=[f2f1]=B2AB2=[1110][f2f1]=[f1+f2f2]=[f3f2]=B3ABn1=[1110][fn1fn2]=[fn2+fn1fn1]=[fnfn1]=BnBn=An1B1=An1[10]

  因为 AAn1 的第一行第二列答案和 An1B1 的第一行第一列答案一样, 所以只需求出 An 即可,答案为矩阵第一行第二列。现在关键是如何快速求出 An ,其实矩阵快速幂跟普通快速幂思想是一样的,不同的地方答案初始化为对角线为 1,其他为 0 的单位矩阵,普通乘法改为矩阵乘法即可,具体操作见代码实现。

代码实现:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2, Mod = 10000;
void Matrix(int a[][2], int b[][2]){//矩阵乘法
    int c[maxn][maxn] = {0};
    for(int i = 0; i < 2; ++i)
        for(int j = 0; j < 2; ++j)
            for(int k = 0; k < 2; ++k)
                c[i][j] =(c[i][j] + a[i][k] * b[k][j]) % Mod;
    for(int i = 0; i < 2; ++i)
        for(int j = 0; j < 2; ++j)
            a[i][j] = c[i][j];
}
//A为转移矩阵,res初始为基础矩阵存储答案
int Pow(int A[][2], int n, int res[][2]){//矩阵快速幂
    for(; n; n >>= 1){
        if(n & 1) Matrix(res, A);
        Matrix(A, A);
    }
    return res[0][1];
}
int main(){
    int N;scanf("%d", &N);
    while(N--){
        int n; scanf("%d", &n);
        //A为转移矩阵,res存储 A^n%10000的结果,初始为基础矩阵
        int A[maxn][maxn] = {1, 1, 1, 0}, res[maxn][maxn]={1, 0, 0, 1};
        printf("%d\n", Pow(A, n, res));
    }
}

矩阵加速

题目描述

  已知一个数列 f,它满足:

fx={1x{1,2,3}fx1+fx3x4

  求 f 数列的第 n 项对 109+7 取余的值。

输入格式

  第一行一个整数 T,表示询问个数。

  以下 T 行,每行一个正整数 n

输出格式

  每行输出一个非负整数表示答案。

样例 1 输入

3
6
8
10

样例 1 输出

4
9
19

数据范围

  • 对于 30% 的数据 n100
  • 对于 60% 的数据 n2×107
  • 对于 100% 的数据 1T1001n2×109

分析

  跟上一题类似,首先我们要构造出初始矩阵、目标矩阵和转移矩阵,首先初始矩阵矩阵显然为 B3=[f3\f2\f1]=[1\1\1] ,根据初始矩阵我们构造出目标矩阵 Bn=[fn\fn1\fn2],那如何构造出转移矩阵呢?显然目标矩阵需要从上一个矩阵 Bn1=[fn1\fn2\fn3] 推导而来,即:[fn\fn1\fn2]=A[fn1\fn2\fn3] 根据递推式,当 n>=4 时,显然有:

(1)fn=fn11+fn20+fn31(2)fn1=fn11+fn20+fn30(3)fn2=fn10+fn21+fn30A=[101100010]

  很容易推出:

(4)B4=AB3(5)B5=AB4(6)(7)Bn=ABn1(8)Bn=An3B3

代码实现

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int Mod = 1e9 + 7;
void Matrix(ll a[][3], ll b[][3]){
    ll c[3][3] = {0};
    for(int i = 0; i < 3; i++)
        for(int j = 0; j < 3; j++)
            for(int k = 0; k < 3; k++)
                c[i][j] = (c[i][j] + a[i][k] * b[k][j]) % Mod;
    for(int i = 0; i < 3; ++i)
        for(int j = 0; j < 3; ++j)
            a[i][j] = c[i][j];
}
void Pow(ll a[][3], int n, ll res[][3]){
    for(; n; n >>= 1){
        if(n & 1) Matrix(res, a);
        Matrix(a, a);
    }
}
void Sol(){
    int T; scanf("%d", &T);
    while(T--){
        int n; scanf("%d", &n);
        if(n <= 3){
            printf("1\n"); continue;
        }
        ll res[3][3] = {1, 0, 0, 0, 1, 0, 0, 0, 1},
            A[3][3] = {1, 0, 1, 1, 0, 0, 0, 1, 0};
        Pow(A, n - 3, res);
        ll ans = (res[0][0] + res[0][1] + res[0][2]) % Mod;
        printf("%lld\n", ans); 
    }
}
int main(){
    Sol();
    return 0;
}

斐波那契前 n 项和

题目描述

  大家都知道 Fibonacci 数列吧,f1=1,f2=1,f3=2,f4=3,,fn=fn1+fn2

现在问题很简单,输入 nm,求 fn 的前 n 项和 Sn mod m

输入格式

  共一行,包含两个整数 nm

输出格式

  输出前 n 项和 Sn mod m 的值。

样例 1 输入

5 1000

样例 1 输出

12

数据范围

  对 100% 数据满足: 1n2×109,1m109+10

方一:分析

  我们先来推推公式:

(1)fn=fn1+fn2=SnSn1(2)fn1=Sn1Sn2(3)fn2=Sn2Sn3(9)(1)(2)(3)  Sn=2Sn1Sn3

结论:对于数列 {fn},若 fi=a1fi1+a2fi2++aif0,那么存在如下结果:

[a1a2ai1ai100001000010]n[fi1fi2f1f0]=[fn+i1fn+i2fn+1fn]

证明:

  当 n=1

[a1a2ai1ai100001000010][fi1fi2f1f0]=[fifi1f2f1]

  显然成立,假设 n=k 结论也成立,两边同时乘以相同矩阵可得:

[a1a2ai1ai100001000010]k+1[fi1fi2f1f0]=[a1a2ai1ai100001000010][fk+i1fk+i2fk+1fk]=[fn+kfn+k1fn+2fn+1]

所以 n=k+1 时也成立。得证。

  由上述结论我们很容易构造出转移矩阵 A=[201\100\010],初始矩阵为 S=[S2§1§0]=[2\1\0]

方二:分析

显然有:S(n)=f(n+2)f(2)

证明:

f(3)=f(1)+f(2)f(1)=f(3)f(2)f(2)=f(4)f(3)f(3)=f(5)f(4)f(n)=f(n+2)f(n+1)S(n)=f(n+2)f(2)

posted @   轩Demonmaster  阅读(560)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示