【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;
}
posted @ 2022-03-23 14:45  あおいSakura  阅读(37)  评论(0编辑  收藏  举报