前置知识
逆矩阵定义
对于两个矩阵 A , B A,B A,B,如果 A × B = E A\times B=E A×B=E(其中 E E E)为单位矩阵,那么我们称 B B B是 A A A的逆矩阵, A A A为可逆矩阵。
实现
前置:单位矩阵( E E E)
单位矩阵的定义:
一个从左上角到右下角的对角线(主对角线)的元素全部为 1 1 1,其余元素全部为 0 0 0的矩阵。
单位矩阵的性质: A × E = E × A = A A\times E=E\times A=A A×E=E×A=A(常用于矩阵快速幂)
前置:矩阵的初等变换
定义矩阵的初等变换:
1. 交 换 矩 阵 中 两 行 / 列 1.交换矩阵中两行/列 1.交换矩阵中两行/列
2. 将 矩 阵 的 一 行 / 列 同 时 乘 一 个 非 零 数 k 2.将矩阵的一行/列同时乘一个非零数k 2.将矩阵的一行/列同时乘一个非零数k
3. 将 矩 阵 的 一 行 / 列 乘 非 零 数 k 后 加 到 另 一 行 / 列 ( 注 意 是 加 到 ) 3.将矩阵的一行/列乘非零数k后加到另一行/列(注意是加到) 3.将矩阵的一行/列乘非零数k后加到另一行/列(注意是加到)
容易看出,矩阵的初等变换是可逆的,并且其逆运算是同一种类型的初等变换。
前置:初等矩阵
初等矩阵的定义:
初等矩阵是指由单位矩阵经过一次初等变换得到的矩阵。初等矩阵的模样可以写一个3阶或者4阶的单位矩阵。
初等矩阵的性质:设 A A A是一个 m × n m\times n m×n的矩阵,那么对 A A A施行一次初等行变换,就等价于在 A A A的左边乘上一个相应的 m m m阶(即 m × m m\times m m×m)的初等矩阵 M M M(即 M × A M\times A M×A)。对 A A A施行一次初等列变换,其结果等价于在 A A A的右边乘以相应的 n n n阶初等矩阵 N N N(即 A × N A\times N A×N)。反之亦然。
对于相应矩阵的解释:如果单位矩阵 E E E做出一种初等变换得到的矩阵为 E ′ E' E′,矩阵 B B B做出同样的变换得到的矩阵为 B ′ B' B′,那么 B ′ = E ′ × B B'=E'\times B B′=E′×B。
初等矩阵一定存在逆矩阵。
矩阵求逆
首先,由矩阵的初等变换可逆得:
如果 A A A存在逆矩阵,那么 A A A可以通过一些初等变换,化为单位矩阵 E E E,即:
P
1
×
P
2
×
.
.
.
×
P
n
×
A
=
E
P_1\times P_2\times ...\times P_n \times A=E
P1×P2×...×Pn×A=E
证明需要用到行列式的相关知识,此处不予提及。
我们在等式两边同时乘上
A
A
A的逆矩阵
A
−
1
A^{-1}
A−1,那么我们有:
P
1
×
P
2
×
.
.
.
×
P
n
=
A
−
1
P_1\times P_2\times ...\times P_n=A^{-1}
P1×P2×...×Pn=A−1
所以我们可以构造一个单位矩阵,在使用高斯消元将
A
A
A转化成单位矩阵是我们同时对该单位矩阵进行同样的操作,最后输出单位矩阵即可。
例题:传送门
解析:用刚才的方法操作就好,分数取模时要求出逆元。
Code
#include<bits/stdc++.h>
#define int long long
#define Mod 1000000007
using namespace std;
int f[405][805];
int ksm(int a,int b){
int res=1;
while(b){
if(b&1) res=res*a%Mod;
a=a*a%Mod;
b>>=1;
}
return res;
}
signed main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
scanf("%lld",&f[i][j]);
}
f[i][i+n]=1;
}
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j++){
if(f[j][i]){
for(int k=1;k<=n*2;k++){
swap(f[i][k],f[j][k]);
}
break;
}
}
if(!f[i][i]){
cout<<"No Solution\n";
return 0;
}
int r=ksm(f[i][i],Mod-2);
for(int j=i;j<=n*2;j++){
f[i][j]=f[i][j]*r%Mod;
}
for(int j=1;j<=n;j++){
if(j!=i){
r=f[j][i];
for(int k=i;k<=n*2;k++){
f[j][k]=(f[j][k]-r*f[i][k]%Mod+Mod)%Mod;
}
}
}
}
for(int i=1;i<=n;i++){
for(int j=n+1;j<=n*2;j++){
printf("%lld ",f[i][j]);
}
printf("\n");
}
}