「矩阵求逆」P4783 【模板】矩阵求逆

知识点:线性代数

Link:Luogu

大家好啊,我不会线代,下学期才开,所以这题抄的,只是简单记录做法,等到学了线代再回来更深一步理解。

但是这做法又易懂又好记又牛逼。

主要抄袭对象:https://www.luogu.com.cn/blog/_post/162629

不过在此之前需要担心一下开学的微积分考试妈的

简述

给定一 n×n 的矩阵 A,判断该矩阵是否可逆,如果可逆则求该矩阵的逆矩阵,答案对 109+7 取模。
1n4000ai,j<109+7
1S,128MB。

分析

这里仅给出一种使用高斯-约旦消元的做法。

[AB] 表示将一个 n×mb 的矩阵 B 拼接一个 n×ma 的矩阵 A 之后形成的矩阵,即有:

[AB]i,j={Ai,j(jma)Bi,jma(ma<jma+mb)

In×n 的单位矩阵,则有:

A1×[AI]=[IA1]

则若我们可以通过对矩阵 [AI] 进行若干操作使得矩阵的左半部分(即拼接后左半边的 A)转化为单位矩阵 I,则我们进行的操作等价于令 A1 乘上了矩阵 [AI],则得到的矩阵的右半部分即为所求的逆矩阵 A1

使用高斯-约旦法将 [AI] 的左半边消成对角矩阵,再令每行除以系数即可。

由于是在模意义下,消元时的除法需要用逆元代替。

总复杂度 O(n3) 级别。

代码

复制复制
//By:Luckyblock
/*
*/
#include <cstdio>
#include <cctype>
#include <algorithm>
#define LL long long
const int kN = 410;
const LL p = 1e9 + 7;
//=============================================================
int n;
LL a[kN][kN << 1];
//=============================================================
inline int read() {
int f = 1, w = 0; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = - 1;
for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + ch - '0';
return f * w;
}
LL qpow(LL x_, LL y_) {
LL ret = 1;
while (y_) {
if (y_ & 1) ret = ret * x_ % p;
x_ = x_ * x_ % p, y_ >>= 1ll;
}
return ret;
}
bool Gauss_jordan() {
for (int i = 1; i <= n; ++ i) {
int pos = i;
for (int j = i + 1; j <= n; ++ j) {
if (a[j][i] > a[pos][i]) pos = j;
}
if (pos != i) std::swap(a[i], a[pos]);
if (!a[i][i]) return false;
LL inv = qpow(a[i][i], p - 2);
for (int j = 1; j <= n; ++ j) {
if (j == i) continue;
LL delta = a[j][i] * inv % p;
for (int k = 1; k <= 2 * n; ++ k) {
a[j][k] = ((a[j][k] - delta * a[i][k]) % p + p) % p;
}
}
for (int j = 1; j <= 2 * n; ++ j) a[i][j] = a[i][j] * inv % p;
}
return true;
}
//=============================================================
int main() {
// freopen("1.txt", "r", stdin);
n = read();
for (int i = 1; i <= n; ++ i) {
for (int j = 1; j <= n; ++ j) {
a[i][j] = read(), a[i][i + n] = 1;
}
}
if (!Gauss_jordan()) {
printf("No Solution\n");
return 0;
}
for (int i = 1; i <= n; ++ i) {
for (int j = n + 1; j <= 2 * n; ++ j) {
printf("%lld ", a[i][j]);
}
printf("\n");
}
return 0;
}
posted @   Luckyblock  阅读(90)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示