前置知识
逆矩阵定义
对于两个矩阵 ,如果 (其中 )为单位矩阵,那么我们称 是 的逆矩阵, 为可逆矩阵。
实现
前置:单位矩阵( )
单位矩阵的定义:
一个从左上角到右下角的对角线(主对角线)的元素全部为 ,其余元素全部为 的矩阵。
单位矩阵的性质: (常用于矩阵快速幂)
前置:矩阵的初等变换
定义矩阵的初等变换:
容易看出,矩阵的初等变换是可逆的,并且其逆运算是同一种类型的初等变换。
前置:初等矩阵
初等矩阵的定义:
初等矩阵是指由单位矩阵经过一次初等变换得到的矩阵。初等矩阵的模样可以写一个3阶或者4阶的单位矩阵。
初等矩阵的性质:设 是一个 的矩阵,那么对 施行一次初等行变换,就等价于在 的左边乘上一个相应的 阶(即 )的初等矩阵 (即 )。对 施行一次初等列变换,其结果等价于在 的右边乘以相应的 阶初等矩阵 (即 )。反之亦然。
对于相应矩阵的解释:如果单位矩阵 做出一种初等变换得到的矩阵为 ,矩阵 做出同样的变换得到的矩阵为 ,那么 。
初等矩阵一定存在逆矩阵。
矩阵求逆
首先,由矩阵的初等变换可逆得:
如果 存在逆矩阵,那么 可以通过一些初等变换,化为单位矩阵 ,即:
证明需要用到行列式的相关知识,此处不予提及。
我们在等式两边同时乘上
的逆矩阵
,那么我们有:
所以我们可以构造一个单位矩阵,在使用高斯消元将
转化成单位矩阵是我们同时对该单位矩阵进行同样的操作,最后输出单位矩阵即可。
例题:传送门
解析:用刚才的方法操作就好,分数取模时要求出逆元。
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");
}
}