矩阵快速幂 笔记

矩阵的运算

矩阵(Matrix)是一个按照长方阵列排列的集合

加法

矩阵的加法必须保证都是同型矩阵即加减运算行列数都必须一样
矩阵的加法运算满足结合律和交换律:
A + B = B + A A+B=B+A A+B=B+A
A + ( B + C ) = ( A + B ) + C A+(B+C)=(A+B)+C A+(B+C)=(A+B)+C

减法同理

数乘

把矩阵A的行和列互相交换所产生的矩阵称为A的转置矩阵
即所有元素都乘一遍一个数

矩阵的加减法和矩阵的数乘合称矩阵的线性运算

共轭

矩阵的共轭指的是将一个复数矩阵每个元素的虚部取负,实部则不变

共轭转制

顾名思义,进行共轭和转制

乘法

乘法运算矩阵行数必须等于第二个矩阵的列数

a 行 b 列的矩阵 × b 行 c 列的矩阵 = a 行 c 列的矩阵 a行b列的矩阵\times b行c列的矩阵=a行c列的矩阵 ab列的矩阵×bc列的矩阵=ac列的矩阵

矩阵的乘法满足结合律,不满足交换律
( a ∗ b ) ∗ c = a ∗ ( b ∗ c ) (a*b)*c=a*(b*c) (ab)c=a(bc)

e.g:
A × B = C A\times B=C A×B=C

A = (    a 1 a 2          a 3 a 4    ) A=\left( \begin{matrix} ~~a1& a2~~ \\ ~~\\ ~~a3 & a4~~ \end{matrix} \right) A=   a1    a3a2  a4  

B = (    b 1 b 2          b 3 b 4    ) B=\left( \begin{matrix} ~~b1& b2~~ \\ ~~\\ ~~b3 & b4~~ \end{matrix} \right) B=   b1    b3b2  b4  

则:

C = (    a 1 × b 1 + a 2 × b 3 a 1 × b 2 + a 2 × b 4          a 3 × b 1 + a 4 × b 3 a 3 × b 2 + a 4 × b 4    ) C=\left( \begin{matrix} ~~a1 \times b1+a2\times b3& a1\times b2+a2\times b4~~ \\ ~~\\ ~~a3\times b1+a4\times b3 & a3\times b2+a4\times b4~~ \end{matrix} \right) C=   a1×b1+a2×b3    a3×b1+a4×b3a1×b2+a2×b4  a3×b2+a4×b4  

转制

行列互换

【模板】矩阵乘法

题目描述

给定两个矩阵 a , b a,b a,b,求矩阵 c = a × b c=a\times b c=a×b

输入描述

第一行四个整数 m 1 , n 1 , m 2 , n 2 m1,n1,m2,n2 m1,n1,m2,n2,代表第一个矩阵和第二个矩阵的列数和行数。

接下来 n 1 n1 n1 行,每行 m 1 m1 m1 个整数,代表第一个矩阵。

之后 n 2 n2 n2 行,每行 m 2 m2 m2 个整数,代表第二个矩阵。

数据保证 m 1 = n 2 m1=n2 m1=n2 。所有的输入数据不超过 100 100 100

输出描述

输出 n 1 n1 n1 行,每行 m 2 m2 m2 个整数,代表矩阵 c c c

样例输入1

2 2 2 2
2 2
2 2
2 2
2 2

样例输出1

8 8
8 8

样例输入2

2 2 2 2
1 2
3 1
2 5
1 7

样例输出2

4 19
7 22

#include
using namespace std;
int n1,m1,n2,m2;
int a[105][105],b[105][105],c[105][105];
void funt(){
	for(int i=1;i<=n1;i++){
		for(int j=1;j<=m2;j++){
			for(int k=1;k<=m1;k++){
				c[i][j]+=a[i][k]*b[k][j];
			}
		}
	}
}
int main(){
	scanf("%d%d%d%d",&m1,&n1,&m2,&n2);
	for(int i=1;i<=n1;i++){
		for(int j=1;j<=m1;j++){
			scanf("%d",&a[i][j]);
		}
	}
	for(int i=1;i<=n2;i++){
		for(int j=1;j<=m2;j++){
			scanf("%d",&b[i][j]);
		}
	}
	funt();
	for(int i=1;i<=n1;i++){
		for(int j=1;j<=m2;j++){
			printf("%d ",c[i][j]);
		}
		printf("\n");
	}
    return 0;
}

【模板】矩阵求和

题目描述

给出两个 n n n m m m 列的矩阵,求两个矩阵的和

输入描述

第一行输入两个以空格分隔的整数 n , m n,m n,m,表示矩阵的行数和列数,接下来的 n n n 行,每行 m m m 个以空格分隔的实数 T 1 [ i ] [ j ] T1[i][j] T1[i][j],表示第一个矩阵,接下来的 n n n 行,每行 m m m 个以空格分隔的实数 T 2 [ i ] [ j ] T2[i][j] T2[i][j] ,表示第二个矩阵
1 ≤ n ≤ 100 , 1 ≤ m ≤ 100 1≤n≤100,1≤m≤100 1n100,1m100
0 ≤ T 1 [ i ] [ j ] ≤ 1000 , 0 ≤ T 2 [ i ] [ j ] ≤ 1000 0≤T1[i][j]≤1000,0≤T2[i][j]≤1000 0T1[i][j]1000,0T2[i][j]1000
cout << fixed << setprecision(2) << x; 或者 printf(“%.2lf”,x); 可以用来输出小数 x x x 并保留两位小数

输出描述

输出 n n n 行,每行包含 m m m 个以空格分隔的实数,表示两个矩阵相加的结果
矩阵中的实数都保留 2 2 2 位小数

样例输入

2 3
1.1 1.2 1.3
2.1 2.2 2.3
1.1 1.2 1.3
2.1 2.2 2.3

样例输出

2.20 2.40 2.60
4.20 4.40 4.60

#include
using namespace std;
int n,m;
double a[105][105],b[105][105],c[105][105];

void funa(){
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			c[i][j]=a[i][j]+b[i][j];
		}
	}
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			scanf("%lf",&a[i][j]);
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			scanf("%lf",&b[i][j]);
		}
	}
	funa();
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			printf("%.2lf ",c[i][j]);
		}
		printf("\n");
	}
    return 0;
}

单位元

如果某个元素 x x x 和其他元素 y y y 做运算,结果依旧是 y y y 那么称其为“单位元”
比如:

集合 运算 单位元
实数 +(加法) 0
实数 ·(乘法) 1
实数 ^(幂) 1(只为右单位元)
矩阵 +(加法) 零矩阵
字串 串接 空字元串
集合M的子集 ∩(交集) M
集合 ∪(并集) { }(空集)
布尔逻辑 ∧(逻辑与) ⊤(真值)
布尔逻辑 ∨(逻辑或) ⊥(假值)

单位矩阵

单位矩阵就是矩阵乘法运算的单位元
单位矩阵是一种特殊的方阵,其主对角线上的元素都为 1 1 1,其他元素都为 0 0 0

以下是关于矩阵的一些功能的框架

#include
using namespace std;
struct Mat{
    int a[105][105];
    int r,c;
    Mat(int _r=0,int _c=0){
        r=_r,c=_c;
        memset(a,0,sizeof a);
        if(c==0)
        	c=r;
    }
    
    Mat operator*(const Mat t)const{
        Mat ans(r,t.c); 
        int n=r,m=t.c;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                for(int k=1;k<=c;k++)
                    ans.a[i][j]+=a[i][k]*t.a[k][j];
        return ans;
    }
    Mat operator+(const Mat t)const{
        Mat ans(r,c);
        for(int i=1;i<=r;i++)
            for(int j=1;j<=c;j++)
                ans.a[i][j]=a[i][j]+t.a[i][j];
        return ans;
    }
    void unit(){
    	memset(a,0,sizeof a);
    	for(int i=1;i<=r;i++){
    		a[i][i]=1;
		}
	}
	
    void print(){
        for(int i=1;i<=r;i++){
            for(int j=1;j<=c;j++)
                cout<<a[i][j]<<" ";
        }
        printf("\n");
    }
    Mat operator %(const int t)const{
		Mat ans= *this;
		for(int i=1;i<=r;i++){
			for(int j=1;j<=c;j++){
				ans.a[i][j]%=t;
			}
		}
		return ans;
	}
	Mat ksm(int x,int p){
		Mat ans(r,c),a= *this;
		ans.unit();
		while(x){
			if(x&1){
				ans=ans*a%p;
			}
			a=a*a%p;
			x>>=1;
		}
		return ans%p;
	}
};
int main(){
	
    return 0;
}

斐波那契数列

题目描述

求出 F n   m o d   1 0 9 + 7 F_n ~mod~10^9 + 7 Fn mod 109+7 的值

输入描述

一个正整数 n ( 1 ≤ n ≤ 2 63 ​ − 1 ) n (1≤n≤2^{63}​ −1) n(1n2631)

输出描述

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

样例输入1

5

样例输出1

5

样例输入2

10

样例输出2

55

#include
using namespace std;
long long n,mod=1e9+7;
struct Mat{
    long long a[105][105];
    long long r,c;
    Mat(int _r=0,int _c=0){
        r=_r,c=_c;
        memset(a,0,sizeof a);
        if(c==0)
        	c=r;
    }
    Mat operator*(const Mat t)const{
        Mat ans(r,t.c); 
        int n=r,m=t.c;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                for(int k=1;k<=c;k++)
                    ans.a[i][j]+=a[i][k]*t.a[k][j];
        return ans;
    }
    Mat operator+(const Mat t)const{
        Mat ans(r,c);
        for(int i=1;i<=r;i++)
            for(int j=1;j<=c;j++)
                ans.a[i][j]=a[i][j]+t.a[i][j];
        return ans;
    }
    void unit(){
    	memset(a,0,sizeof a);
    	for(int i=1;i<=r;i++){
    		a[i][i]=1;
		}
	}
    void print(){
        for(int i=1;i<=r;i++){
            for(int j=1;j<=c;j++)
                cout<<a[i][j]<<" ";
        }
        printf("\n");
    }
    Mat operator %(const int t)const{
		Mat ans= *this;
		for(int i=1;i<=r;i++){
			for(int j=1;j<=c;j++){
				ans.a[i][j]%=t;
			}
		}
		return ans;
	}
	Mat ksm(long long x,long long p){
		Mat ans(r,c),a= *this;
		ans.unit();
		while(x){
			if(x&1){
				ans=ans*a%p;
			}
			a=a*a%p;
			x>>=1;
		}
		return ans%p;
	}
};
int main(){
	scanf("%lld",&n);
	Mat a(2,2),b(2,2);
	if(n<=2){
		printf("1");
		return 0;
	}
	a.a[1][1]=a.a[1][2]=1;
	b.a[1][1]=b.a[1][2]=b.a[2][1]=1;
	b.a[2][2]=0;
	a=a*b.ksm(n-2,mod)%mod;
	printf("%lld",a.a[1][1]);
    return 0;
}

【模板】矩阵加速

题目描述
P1939 矩阵加速(数列)

#include
using namespace std;
long long n,mod=1e9+7;
struct Mat{
    long long a[105][105];
    long long r,c;
    Mat(int _r=0,int _c=0){
        r=_r,c=_c;
        memset(a,0,sizeof a);
        if(c==0)
        	c=r;
    }
    Mat operator*(const Mat t)const{
        Mat ans(r,t.c); 
        int n=r,m=t.c;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                for(int k=1;k<=c;k++)
                    ans.a[i][j]+=a[i][k]*t.a[k][j];
        return ans;
    }
    Mat operator+(const Mat t)const{
        Mat ans(r,c);
        for(int i=1;i<=r;i++)
            for(int j=1;j<=c;j++)
                ans.a[i][j]=a[i][j]+t.a[i][j];
        return ans;
    }
    void unit(){
    	memset(a,0,sizeof a);
    	for(int i=1;i<=r;i++){
    		a[i][i]=1;
		}
	}
    void print(){
        for(int i=1;i<=r;i++){
            for(int j=1;j<=c;j++)
                cout<<a[i][j]<<" ";
        }
        printf("\n");
    }
    Mat operator %(const int t)const{
		Mat ans= *this;
		for(int i=1;i<=r;i++){
			for(int j=1;j<=c;j++){
				ans.a[i][j]%=t;
			}
		}
		return ans;
	}
	Mat ksm(long long x,long long p){
		Mat ans(r,c),a= *this;
		ans.unit();
		while(x){
			if(x&1){
				ans=ans*a%p;
			}
			a=a*a%p;
			x>>=1;
		}
		return ans%p;
	}
};
int main(){
	int T;
	Mat a(5,5);
	scanf("%d",&T);
	while(T--){
		scanf("%lld",&n); 
		memset(a.a,0,sizeof(a.a));
		if(n<=3){
			printf("1\n");
			continue;
		}
		a.a[1][1]=1;
	    a.a[3][1]=1;
	    a.a[1][2]=1;
	    a.a[2][3]=1;
		a=a*a.ksm(n,mod)%mod;
		printf("%lld\n",a.a[2][1]);
	}
    return 0;
}

你可能感兴趣的:(矩阵,笔记,算法)