行列式
定义
对于一个 \(n\) 阶方阵 \(A\),其行列式 \(|A|\)(也写为 \(\det A\))定义为:
\[\sum_p(-1)^{\tau(p)}\prod_{i=1}^n a_{i,p_i}
\]
其中 \(\sum_p\) 表示对 \(1,2,\cdots,n\) 的所有全排列 \(p\) 求和,\(\tau(p)\) 表示 \(p\) 的逆序对数。
形如:(未填的位置为 \(0\))
\[\left|\begin{matrix}
a_{11} \\
a_{21} & a_{22}\\
\vdots & \vdots & \ddots\\
a_{n1} & a_{n2} & \cdots & a_{nn}
\end{matrix}\right|=\prod_{i=1}^na_{ii}
\]
的行列式称为下三角行列式,上三角行列式的定义同理。
性质
性质一 行列式与它的转置行列式相等。
即:
\[\left|\begin{matrix}
a_{11} & a_{12} & \cdots & a_{1n}\\
a_{21} & a_{22} & \cdots &a_{2n}\\
\vdots & \vdots & \ddots & \vdots\\
a_{n1} & a_{n2} & \cdots & a_{nn}
\end{matrix}\right|
=
\left|\begin{matrix}
a_{11} & a_{21} & \cdots & a_{n1}\\
a_{12} & a_{22} & \cdots &a_{n2}\\
\vdots & \vdots & \ddots & \vdots\\
a_{1n} & a_{2n} & \cdots & a_{nn}
\end{matrix}\right|
\]
性质二 对换行列式的两行或两列,行列式变号。
性质三 行列式的某一行或某一列中所有的元素都乘以同一数 \(k\),等于用 \(k\) 乘以行列式。
即:
\[\left|\begin{matrix}
a_{11} & a_{12} & \cdots & a_{1n}\\
\vdots & \vdots & & \vdots\\
ka_{r1} & ka_{r2} & \cdots & ka_{rn}\\
\vdots & \vdots & & \vdots\\
a_{n1} & a_{n2} & \cdots & a_{nn}
\end{matrix}\right|=
k\left|\begin{matrix}
a_{11} & a_{12} & \cdots & a_{1n}\\
\vdots & \vdots & & \vdots\\
a_{r1} & a_{r2} & \cdots & a_{rn}\\
\vdots & \vdots & & \vdots\\
a_{n1} & a_{n2} & \cdots & a_{nn}
\end{matrix}\right|
\]
列同理。
性质四 行列式的某一行或某一列同乘以一个数然后加到另一行或另一列对应的元素上去,行列式不变。
即:
\[\left|\begin{matrix}
a_{11} & a_{12} & \cdots & a_{1n}\\
\vdots & \vdots & & \vdots\\
a_{i1} & a_{i2} & \cdots & a_{in}\\
\vdots & \vdots & & \vdots\\
a_{j1} & a_{j2} & \cdots & a_{jn}\\
\vdots & \vdots & & \vdots\\
a_{n1} & a_{n2} & \cdots & a_{nn}
\end{matrix}\right|
=
\left|\begin{matrix}
a_{11} & a_{12} & \cdots & a_{1n}\\
\vdots & \vdots & & \vdots\\
a_{i1} & a_{i2} & \cdots & a_{in}\\
\vdots & \vdots & & \vdots\\
a_{j1}+ka_{i1} & a_{j2}+ka_{i2} & \cdots & a_{jn}+ka_{in}\\
\vdots & \vdots & & \vdots\\
a_{n1} & a_{n2} & \cdots & a_{nn}
\end{matrix}\right|
\]
列同理。
性质五 \(\det(AB)=\det A\det B\)
即 NOI2021 D1T2。
以上诸性质的证明留给读者练习
行列式求值
根据性质二三四,可以使用高斯消元将一般行列式转换为上三角或者下三角的形式,答案就是正对角线上所有数之积。
模板题:Luogu P7112
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=610;
int n,mod;
struct mat
{
int a[N][N];
mat(){memset(a,0,sizeof(a));}
mat operator *(const mat &x)const
{
mat ans;
for(int k=1;k<=n;k++)for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)
ans.a[i][j]+=1ll*a[i][k]*x.a[k][j]%mod,ans.a[i][j]%=mod;
return ans;
}
void init(){for(int i=1;i<=n;i++)a[i][i]=1;}
};
inline int read()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return x*f;
}
int det(mat x)
{
int ans=1;
for(int i=1;i<=n;i++)
{
for(int j=i+1;j<=n;j++)
{
while(x.a[i][i])
{
int rate=x.a[j][i]/x.a[i][i];
for(int k=1;k<=n;k++)
x.a[j][k]=(x.a[j][k]-1ll*rate*x.a[i][k]%mod+mod)%mod;
for(int k=1;k<=n;k++)swap(x.a[i][k],x.a[j][k]);
ans*=-1;
}
ans*=-1;
for(int k=1;k<=n;k++)swap(x.a[i][k],x.a[j][k]);
}
}
for(int i=1;i<=n;i++)ans=1ll*ans*x.a[i][i]%mod;
return (ans+mod)%mod;
}
int main()
{
n=read(),mod=read();
mat x;
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)x.a[i][j]=read();
printf("%d\n",det(x));
return 0;
}