【luogu P4783】【模板】矩阵求逆(高斯消元)
【模板】矩阵求逆
题目链接:luogu P4783
题目大意
给你一个 n*n 的矩阵,要你求它的逆矩阵。
思路
也就是要找一个矩阵使得 \(AB=E\)(\(E\) 就是单位矩阵)。
然后你考虑弄三种矩阵的初等行变换。
交换两行。
某一行乘上 \(k\)。
某一行加上某一行乘 \(k\)。
然后你考虑通过变换让 \(A\) 变成 \(E\),然后这些操作就交给 \(B\),也就可以把一个 \(E\) 变成我们要的 \(B\) 了。
然后就用类似高斯消元,判无解的方法也跟高斯消元一样。
然后搞就好啦。
代码
#include<cstdio>
#include<algorithm>
#define ll long long
#define mo 1000000007
using namespace std;
const int N = 400 + 1;
int n;
struct node {
ll a[N][N];
void Swap(int x, int y) {
for (int i = 1; i <= n; i++) swap(a[x][i], a[y][i]);
}
void Times(int x, ll k) {
k = (k % mo + mo) % mo;
for (int i = 1; i <= n; i++)
a[x][i] = a[x][i] * k % mo;
}
void Mul(int x, int y, ll k) {
k = (k % mo + mo) % mo;
for (int i = 1; i <= n; i++)
a[x][i] = (a[x][i] + a[y][i] * k % mo) % mo;
}
}A, B;
ll ksm(ll x, ll y) {
ll re = 1;
while (y) {
if (y & 1) re = re * x % mo;
x = x * x % mo; y >>= 1;
}
return re;
}
ll inv(ll x) {
return ksm(x, mo - 2);
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
scanf("%lld", &A.a[i][j]);
for (int i = 1; i <= n; i++) B.a[i][i] = 1;
for (int i = 1; i <= n; i++) {
for (int j = i + 1; j <= n; j++)
if (A.a[j][i]) {
A.Swap(i, j); B.Swap(i, j); break;
}
if (!A.a[i][i]) {
printf("No Solution"); return 0;
}
ll x = A.a[i][i]; x = inv(x);
A.Times(i, x); B.Times(i, x);
for (int j = i + 1; j <= n; j++) {
x = -A.a[j][i];
A.Mul(j, i, x); B.Mul(j, i, x);
}
}
for (int i = n; i >= 1; i--)
for (int j = i + 1; j <= n; j++) {
ll x = -A.a[i][j];
A.Mul(i, j, x); B.Mul(i, j, x);
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) printf("%lld ", B.a[i][j]);
puts("");
}
return 0;
}