题解 P4783 【【模板】矩阵求逆】


这是一道线性代数的好题

调死我这个大菜鸡了

如果您还不太清楚线性代数的话,那么我可以跟您讲一个笑话:

有人在盘点世界上吊死人最多的树
据说是美国还是法国的哪片森林里的
其实这完全是瞎扯
他们怕是不知道,有一种叫做“线性代数”的树
上面吊死的人远比那些树多得多

嗯嗯,笑话讲完了,我们来做题吧qwq

在看这篇题解之前,需要了解的芝士:

1.高斯-约旦消元法

2.矩阵的基本知识(矩阵的初等变换,单位矩阵等等)

应该都好理解的吧(至于我为什么不用高斯消元,是因为我个人认为,高斯消元的精度不是很高,代码有些长 所以不好背


首先来讲一讲什么是矩阵求逆

题目告诉我们一个矩阵\(A\),让我们求得一个矩阵\(B\),使得\(AB=BA=I\)

那么问题来了,这个矩阵\(I\)是个smg?

矩阵\(I\)就是传说中的单位矩阵

这是一个\(4\times4\)的单位矩阵

\[I=\begin{bmatrix}1&0&0&0\\0&1&0&0\\0&0&1&0\\0&0&0&1\end{bmatrix} \]

看到了嘛,单位矩阵就是一条对角线上都是1,余都为0的矩阵。

说白了,就是求\(B=I/A\)这个东西

可惜好像矩阵运算里没有除法

我上面那个表达式也是不合法的

然后我们就会用BFS(Baidu First Search)去找思路

求逆思路:

1.把\(A\)和它等大的单位矩阵\(I\)放在一个矩阵里

2.对\(A\)进行高斯消元使\(A\)化成单位矩阵

3.此时原来单位矩阵转化成逆矩阵

意不意外?惊不惊喜?

知道了具体的过程,我们就可以来搞事情了,把P3389的程序复制粘贴过来……

然后修改一下,加上右边的矩阵\(I\),修改一下输出,然后……

\({\color{Red}WA}\)

是我沙雕了……两个题目的数据类型都不一样啊啊啊啊啊啊啊

高斯消元是\(Double\)的,但是这道题……\(long\;long\)……

还带着除法……

所以话说乘法逆元是个好东西

然后把数据类型改一下,写个龟速幂套乘法逆元,然后……

\({\color{Red}WA}\)

嘤嘤嘤嘤嘤嘤嘤嘤嘤嘤嘤嘤嘤嘤嘤嘤嘤嘤……

然后我借鉴了一下题解,发现是%运算的锅,因为这个很可能出现负数,然后就会\({\color{Red}WA}\)掉。

比如我的\({\color{green}AC}\)程序里有这个:

a[j][k]=(a[j][k]%mod+mod)%mod;

和之前\({\color{red}WA}\)这个:

a[j][k]%=mod;

是不一样的。

上面的那个确保了没有负数(Maybe

所以说,%这个运算最好用在膜拜管理员/神仙/巨佬中,如果题目里有模数,那么……我多半会挂掉……

\({\color{green}AC}\)程序:

#include 
using namespace std;
const long long mod=1e9+7;
long long a[500][1000];
long long IE(long long m,long long n)
{
  long long p=1;
  while(n)
  {
    if(n%2==1) p=(p*m)%mod;
    m=m*m%mod;
    n/=2;
  }
  return p%mod;
}
int main()
{
  long long n;
  cin>>n;
  for(int i=1; i<=n; i++)
    for(int j=1; j<=n; j++)
      cin>>a[i][j];
  for(int i=1; i<=n; i++) a[i][i+n]=1;
  for(int i=1; i<=n; i++)
  {
    int tx=i;
    for(int j=i+1; j<=n; j++)
      if(abs(a[j][i])>abs(a[tx][i])) tx=j;
    if(i!=tx)
    {
      for(int j=1; j<=n*2; j++)
        swap(a[i][j],a[tx][j]);
    }
    if(!a[i][i])
    {
      cout<<"No Solution";
      return 0;
    }
    int I=IE(a[i][i],mod-2);
    for (int j=1; j<=n; j++)
      if(j!=i)
      {
        long long t=a[j][i]*I%mod;
        for (int k=i; k<=n*2; k++)
        {
          a[j][k]-=a[i][k]*t;
          a[j][k]=(a[j][k]%mod+mod)%mod;
        }
      }
    for(int j=1; j<=2*n; j++)
      a[i][j]=a[i][j]*I%mod;
  }
  for(int i=1; i<=n; i++)
  {
    for(int j=n+1; j<=n*2; j++)
      cout<

就是这样子吧……线性代数真的是毒瘤……喵喵喵~~~