由于马上准备学 eert-xirtam 定理要用到这玩意儿所以就来学了
upd on 2021.6.29:修了个大错误(
定义:对于一个 \(n\times n\) 的矩阵 \(A\) 定义其行列式为 \(\sum\limits_{p_1,p_2,\cdots,p_n}(-1)^{\tau(p)}\prod\limits_{i=1}^nA_{i,p_i}\),其中 \(p\) 为一个 \(1\sim n\) 的排列,\(\tau(p)\) 表示 \(p\) 的逆序对数,记作 \(\det A\),也可写作 \(\begin{vmatrix}A_{1,1}&A_{1,2}&\cdots&A_{1,n}\\A_{2,1}&A_{2,2}&\cdots&A_{2,n}\\\vdots&\vdots&\ddots&\vdots\\A_{n,1}&A_{n,2}&\cdots&A_{n,n}\end{vmatrix}\)。
根据行列式的定义暴力计算显然是 \(n!·n\) 的,不过利用行列式的一些性质可减少计算量。
下面我们就来看行列式的一些性质:
性质 1:对角矩阵的行列式为其对角元素的乘积
即 \(\begin{vmatrix}A_{1,1}&0&\cdots&0\\0&A_{2,2}&\cdots&0\\\vdots&\vdots&\ddots&\vdots\\0&0&\cdots&A_{n,n}\end{vmatrix}=\prod\limits_{i=1}^nA_{i,i}\)。
证明:显然。因为只有 \(p_i=i\) 的贡献非零。
同理上三角矩阵、下三角矩阵的行列式也为其对角元素的乘积。
性质 2:对于任意矩阵 \(A\),\(\det A=\det A^T\)
即 \(\begin{vmatrix}A_{1,1}&A_{1,2}&\cdots&A_{1,n}\\A_{2,1}&A_{2,2}&\cdots&A_{2,n}\\\vdots&\vdots&\ddots&\vdots\\A_{n,1}&A_{n,2}&\cdots&A_{n,n}\end{vmatrix}=\begin{vmatrix}A_{1,1}&A_{2,1}&\cdots&A_{n,1}\\A_{1,2}&A_{2,2}&\cdots&A_{n,2}\\\vdots&\vdots&\ddots&\vdots\\A_{1,n}&A_{2,n}&\cdots&A_{n,n}\end{vmatrix}\)
证明:对于任意排列 \(p_1,p_2,\cdots,p_n\),显然其会对 \(\det A\) 产生 \((-1)^{\tau(p)}\prod\limits_{i=1}^nA_{i,p_i}\) 的贡献,考虑一个映射的思想,考虑其乘法逆 \(p^{-1}\),同理可得 \(p^{-1}\) 会对 \(\det A^T\) 产生 \((-1)^{\tau(p^{-1})}\prod\limits_{i=1}^nA^T_{i,p^{-1}_i}\),显然右边的 \(\prod\) 就等于 \(\prod\limits_{i=1}^nA_{p^{-1}_i,i}=\prod\limits_{i=1}^nA_{i,p_i}\),而对于 \(p\) 中的所有逆序对 \(i<j,p_i>p_j\) 都对应 \(p^{-1}\) 中的 \(p_j<p_i,j=p^{-1}_{p_j}>p^{-1}_{p_i}=i\),\(p^{-1}\to p\) 也同理,故 \(\tau(p)=\tau(p^{-1})\)。又显然 \(p,p^{-1}\) 形成双射,也就是说 \((-1)^{\tau(p)}\prod\limits_{i=1}^nA_{i,p_i}\) 对 \(\det A\) 与 \((-1)^{\tau(p^{-1})}\prod\limits_{i=1}^nA^T_{i,p^{-1}_i}\) 对 \(\det A^T\) 的贡献是一一对应的,故 \(\det A=\det A^T\)
性质 3:对于任意矩阵 \(A\),将任意一行中所有元素同时乘上 \(k\) 后 \(\det A\) 也乘 \(k\)
即 \(\begin{vmatrix}A_{1,1}&A_{1,2}&\cdots&A_{1,n}\\A_{2,1}&A_{2,2}&\cdots&A_{2,n}\\\vdots&\vdots&\ddots&\vdots\\kA_{i,1}&kA_{i,2}&\cdots&kA_{i,n}\\\vdots&\vdots&\ddots&\vdots\\A_{n,1}&A_{n,2}&\cdots&A_{n,n}\end{vmatrix}=k\begin{vmatrix}A_{1,1}&A_{1,2}&\cdots&A_{1,n}\\A_{2,1}&A_{2,2}&\cdots&A_{2,n}\\\vdots&\vdots&\ddots&\vdots\\A_{i,1}&A_{i,2}&\cdots&A_{i,n}\\\vdots&\vdots&\ddots&\vdots\\A_{n,1}&A_{n,2}&\cdots&A_{n,n}\end{vmatrix}\)
证明:考虑将行列式定义式大力展开:
得证。
性质 4:对于三个 \(n\times n\) 的矩阵 \(A,B,C\),若 \(\exists i,\forall j,A_{i,j}=B_{i,j}+C_{i,j}\),且 \(\forall k\ne i,j,A_{i,j}=B_{i,j}=C_{i,j}\) 那么 \(\det A=\det B+\det C\)
即 \(\begin{vmatrix}A_{1,1}&A_{1,2}&\cdots&A_{1,n}\\A_{2,1}&A_{2,2}&\cdots&A_{2,n}\\\vdots&\vdots&\ddots&\vdots\\A_{i,1}+B_1&A_{i,2}+B_2&\cdots&A_{i,n}+B_n\\\vdots&\vdots&\ddots&\vdots\\A_{n,1}&A_{n,2}&\cdots&A_{n,n}\end{vmatrix}=\begin{vmatrix}A_{1,1}&A_{1,2}&\cdots&A_{1,n}\\A_{2,1}&A_{2,2}&\cdots&A_{2,n}\\\vdots&\vdots&\ddots&\vdots\\A_{i,1}&A_{i,2}&\cdots&A_{i,n}\\\vdots&\vdots&\ddots&\vdots\\A_{n,1}&A_{n,2}&\cdots&A_{n,n}\end{vmatrix}+\begin{vmatrix}A_{1,1}&A_{1,2}&\cdots&A_{1,n}\\A_{2,1}&A_{2,2}&\cdots&A_{2,n}\\\vdots&\vdots&\ddots&\vdots\\B_1&B_2&\cdots&B_n\\\vdots&\vdots&\ddots&\vdots\\A_{n,1}&A_{n,2}&\cdots&A_{n,n}\end{vmatrix}\)
证明上述命题也可将行列式大力展开:
性质 5:交换两行,行列式反号
即 \(\begin{vmatrix}A_{1,1}&A_{1,2}&\cdots&A_{1,n}\\A_{2,1}&A_{2,2}&\cdots&A_{2,n}\\\vdots&\vdots&\ddots&\vdots\\A_{j,1}&A_{j,2}&\cdots&A_{j,n}\\\vdots&\vdots&\ddots&\vdots\\A_{i,1}&A_{i,2}&\cdots&A_{i,n}\\\vdots&\vdots&\ddots&\vdots\\A_{n,1}&A_{n,2}&\cdots&A_{n,n}\end{vmatrix}=-\begin{vmatrix}A_{1,1}&A_{1,2}&\cdots&A_{1,n}\\A_{2,1}&A_{2,2}&\cdots&A_{2,n}\\\vdots&\vdots&\ddots&\vdots\\A_{i,1}&A_{i,2}&\cdots&A_{i,n}\\\vdots&\vdots&\ddots&\vdots\\A_{j,1}&A_{j,2}&\cdots&A_{j,n}\\\vdots&\vdots&\ddots&\vdots\\A_{n,1}&A_{n,2}&\cdots&A_{n,n}\end{vmatrix}\)
我们先证明一个 Lemma:对于一个排列 \(p\),交换 \(p_i,p_j(i\ne j)\) 后逆序对个数的奇偶性发生变化。
证明:不妨设 \(i<j\),那么可以分出两种情况,\(p_i>p_j\) 和 \(p_i<p_j\),这里以 \(p_i>p_j\) 为例,\(p_i<p_j\) 的情况也同理。
显然对于 \(k<i\) 或 \(k>j\),其中一个位置是 \(k\) 的逆序对数量必定不会发生变化,也就是说发生变化的逆序对只可能在 \([i,j]\) 中,显然交换 \(p_i,p_j\) 后原来的逆序对 \((i,j)\) 会消失,而对于 \(k\in(i,j)\),包含 \(k\) 的逆序对个数会发生变化当且仅当 \(p_j<p_k<p_i\)——有两个逆序对 \((j,k),(k,i)\) 会消失,也就是说变化的逆序对数量永远是奇数,符合题意。
接下来考虑原命题。记原来的矩阵为 \(A\),交换第 \(i,j\) 两行后的矩阵为 \(A'\),我们考虑一个排列 \(p\),我们设 \(p\) 交换 \(p_i,p_j\) 两个元素后得到的排列为 \(p'\),那么 \(p\) 对 \(\det A\) 的贡献应为 \((-1)^{\tau(p)}\prod\limits_{i=1}^nA_{i,p_i}\),\(p'\) 对 \(\det A'\) 的贡献应为 \((-1)^{\tau(p')}\prod\limits_{i=1}^nA_{i,p'_i}\),显然后面的 \(\prod\) 里面的东西是相等的,而根据 Lemma,\(\tau(p),\tau(p')\) 奇偶性相反,故 \((-1)^{\tau(p)}+(-1)^{\tau(p')}=0\),故 \(p\) 对 \(\det A\) 的贡献与 \(p'\) 对 \(\det A'\) 的贡献互为相反数,即 \(\det A'=-\det A\)。
性质 6:如果矩阵 \(A\) 存在两行成比例,那么 \(\det A=0\)
即对于矩阵 \(A\),如果 \(\exist i,j,\lambda\) 满足 \(\forall t,A_{j,t}=\lambda A_{i,t}\),那么 \(\det A=0\)。
证明:假设矩阵为 \(\begin{bmatrix}A_{1,1}&A_{1,2}&\cdots&A_{1,n}\\A_{2,1}&A_{2,2}&\cdots&A_{2,n}\\\vdots&\vdots&\ddots&\vdots\\A_{i,1}&A_{i,2}&\cdots&A_{i,n}\\\vdots&\vdots&\ddots&\vdots\\\lambda A_{i,1}&\lambda A_{i,2}&\cdots&\lambda A_{i,n}\\\vdots&\vdots&\ddots&\vdots\\A_{n,1}&A_{n,2}&\cdots&A_{n,n}\end{bmatrix}\)
根据性质 3,\(\begin{vmatrix}A_{1,1}&A_{1,2}&\cdots&A_{1,n}\\A_{2,1}&A_{2,2}&\cdots&A_{2,n}\\\vdots&\vdots&\ddots&\vdots\\A_{i,1}&A_{i,2}&\cdots&A_{i,n}\\\vdots&\vdots&\ddots&\vdots\\\lambda A_{i,1}&\lambda A_{i,2}&\cdots&\lambda A_{i,n}\\\vdots&\vdots&\ddots&\vdots\\A_{n,1}&A_{n,2}&\cdots&A_{n,n}\end{vmatrix}=\dfrac{1}{\lambda}\begin{vmatrix}A_{1,1}&A_{1,2}&\cdots&A_{1,n}\\A_{2,1}&A_{2,2}&\cdots&A_{2,n}\\\vdots&\vdots&\ddots&\vdots\\\lambda A_{i,1}&\lambda A_{i,2}&\cdots&\lambda A_{i,n}\\\vdots&\vdots&\ddots&\vdots\\\lambda A_{i,1}&\lambda A_{i,2}&\cdots&\lambda A_{i,n}\\\vdots&\vdots&\ddots&\vdots\\A_{n,1}&A_{n,2}&\cdots&A_{n,n}\end{vmatrix}\)
记 \(A'=\begin{bmatrix}A_{1,1}&A_{1,2}&\cdots&A_{1,n}\\A_{2,1}&A_{2,2}&\cdots&A_{2,n}\\\vdots&\vdots&\ddots&\vdots\\\lambda A_{i,1}&\lambda A_{i,2}&\cdots&\lambda A_{i,n}\\\vdots&\vdots&\ddots&\vdots\\\lambda A_{i,1}&\lambda A_{i,2}&\cdots&\lambda A_{i,n}\\\vdots&\vdots&\ddots&\vdots\\A_{n,1}&A_{n,2}&\cdots&A_{n,n}\end{bmatrix}\),显然 \(A'\) 交换 \(i,j\) 两行之后还是 \(A'\),而根据性质 5,\(\det A'=-\det A'\),故 \(\det A'=0\),故 \(\begin{vmatrix}A_{1,1}&A_{1,2}&\cdots&A_{1,n}\\A_{2,1}&A_{2,2}&\cdots&A_{2,n}\\\vdots&\vdots&\ddots&\vdots\\A_{i,1}&A_{i,2}&\cdots&A_{i,n}\\\vdots&\vdots&\ddots&\vdots\\\lambda A_{i,1}&\lambda A_{i,2}&\cdots&\lambda A_{i,n}\\\vdots&\vdots&\ddots&\vdots\\A_{n,1}&A_{n,2}&\cdots&A_{n,n}\end{vmatrix}=\dfrac{1}{\lambda}\det A'=0\)
顺带提一句,结合下面的结论 7 可知,\(\det A=0\) 的充要条件是 \(A\) 每行组成的向量(不知道这样表述是否规范?)能够形成一个线性相关集。
结论 7:将矩阵的某一行倍加到另一行上去,行列式不变
即对于任意 \(i\ne j\) 及 \(\lambda\ne 0\),都有 \(\begin{vmatrix}A_{1,1}&A_{1,2}&\cdots&A_{1,n}\\A_{2,1}&A_{2,2}&\cdots&A_{2,n}\\\vdots&\vdots&\ddots&\vdots\\A_{i,1}&A_{i,2}&\cdots&A_{i,n}\\\vdots&\vdots&\ddots&\vdots\\A_{j,1}&A_{j,2}&\cdots&A_{j,n}\\\vdots&\vdots&\ddots&\vdots\\A_{n,1}&A_{n,2}&\cdots&A_{n,n}\end{vmatrix}=\begin{vmatrix}A_{1,1}&A_{1,2}&\cdots&A_{1,n}\\A_{2,1}&A_{2,2}&\cdots&A_{2,n}\\\vdots&\vdots&\ddots&\vdots\\A_{i,1}&A_{i,2}&\cdots&A_{i,n}\\\vdots&\vdots&\ddots&\vdots\\A_{j,1}+\lambda A_{i,1}&A_{j,2}+\lambda A_{i,2}&\cdots&A_{j,n}+\lambda A_{i,n}\\\vdots&\vdots&\ddots&\vdots\\A_{n,1}&A_{n,2}&\cdots&A_{n,n}\end{vmatrix}\)
证明:根据性质 4,\(\begin{vmatrix}A_{1,1}&A_{1,2}&\cdots&A_{1,n}\\A_{2,1}&A_{2,2}&\cdots&A_{2,n}\\\vdots&\vdots&\ddots&\vdots\\A_{i,1}&A_{i,2}&\cdots&A_{i,n}\\\vdots&\vdots&\ddots&\vdots\\A_{j,1}+\lambda A_{i,1}&A_{j,2}+\lambda A_{i,2}&\cdots&A_{j,n}+\lambda A_{i,n}\\\vdots&\vdots&\ddots&\vdots\\A_{n,1}&A_{n,2}&\cdots&A_{n,n}\end{vmatrix}=\begin{vmatrix}A_{1,1}&A_{1,2}&\cdots&A_{1,n}\\A_{2,1}&A_{2,2}&\cdots&A_{2,n}\\\vdots&\vdots&\ddots&\vdots\\A_{i,1}&A_{i,2}&\cdots&A_{i,n}\\\vdots&\vdots&\ddots&\vdots\\A_{j,1}&A_{j,2}&\cdots&A_{j,n}\\\vdots&\vdots&\ddots&\vdots\\A_{n,1}&A_{n,2}&\cdots&A_{n,n}\end{vmatrix}+\begin{vmatrix}A_{1,1}&A_{1,2}&\cdots&A_{1,n}\\A_{2,1}&A_{2,2}&\cdots&A_{2,n}\\\vdots&\vdots&\ddots&\vdots\\A_{i,1}&A_{i,2}&\cdots&A_{i,n}\\\vdots&\vdots&\ddots&\vdots\\\lambda A_{i,1}&\lambda A_{i,2}&\cdots&\lambda A_{i,n}\\\vdots&\vdots&\ddots&\vdots\\A_{n,1}&A_{n,2}&\cdots&A_{n,n}\end{vmatrix}\)
根据性质 6,\(\begin{vmatrix}A_{1,1}&A_{1,2}&\cdots&A_{1,n}\\A_{2,1}&A_{2,2}&\cdots&A_{2,n}\\\vdots&\vdots&\ddots&\vdots\\A_{i,1}&A_{i,2}&\cdots&A_{i,n}\\\vdots&\vdots&\ddots&\vdots\\\lambda A_{i,1}&\lambda A_{i,2}&\cdots&\lambda A_{i,n}\\\vdots&\vdots&\ddots&\vdots\\A_{n,1}&A_{n,2}&\cdots&A_{n,n}\end{vmatrix}=0\)
故 \(\begin{vmatrix}A_{1,1}&A_{1,2}&\cdots&A_{1,n}\\A_{2,1}&A_{2,2}&\cdots&A_{2,n}\\\vdots&\vdots&\ddots&\vdots\\A_{i,1}&A_{i,2}&\cdots&A_{i,n}\\\vdots&\vdots&\ddots&\vdots\\A_{j,1}+\lambda A_{i,1}&A_{j,2}+\lambda A_{i,2}&\cdots&A_{j,n}+\lambda A_{i,n}\\\vdots&\vdots&\ddots&\vdots\\A_{n,1}&A_{n,2}&\cdots&A_{n,n}\end{vmatrix}=\begin{vmatrix}A_{1,1}&A_{1,2}&\cdots&A_{1,n}\\A_{2,1}&A_{2,2}&\cdots&A_{2,n}\\\vdots&\vdots&\ddots&\vdots\\A_{i,1}&A_{i,2}&\cdots&A_{i,n}\\\vdots&\vdots&\ddots&\vdots\\A_{j,1}&A_{j,2}&\cdots&A_{j,n}\\\vdots&\vdots&\ddots&\vdots\\A_{n,1}&A_{n,2}&\cdots&A_{n,n}\end{vmatrix}\)
高速求行列式的方法
注意到结论 7 和高斯消元有很大的联系,并且注意到对于一个上三角矩阵,其行列式我们是可以在 \(\mathcal O(n)\) 的时间内求出的,因此我们可以像高斯消元那样把给定的矩阵削消成上三角矩阵,并且由于交换两行,行列式只有符号会发生变化,我们可以记录一个 \(sgn\) 变量表示交换次数的奇偶性,求出消好的上三角矩阵的行列式后乘上 \((-1)^{sgn}\) 即可。
具体来说我们依次考虑每一列,假设我们当前考虑到第 \(i\) 列我们考虑用第 \(i\) 行的第 \(i\) 个未知数将第 \(i+1,i+2,\cdots,n\) 行的第 \(i\) 个未知数消掉,消元的方法异常 simple,只需将第 \(i\) 行乘上 \(-\dfrac{A_{j,i}}{A_{i,i}}\) 倍加到第 \(j\) 行上去即可,当然也有可能出现 \(A_{i,i}=0\) 的情况,此时我们就在 \(i+1,i+2,\cdots,n\) 中找到一个 \(A_{j,i}\ne 0\) 的 \(j\) 并交换 \(i,j\) 两行即可,注意令 \(sgn\) 加一。
这里有一个小小的注意点,就是消元的时候我们不能真的开 double
类型消元,否则可能会爆精度,当然如果模数是质数的话可以使用费马小定理求逆元。那如果模数不是质数怎么办呢?这里有一个方法叫辗转消元法,假设我们要把 \(A_{j,i}\) 消掉,那么我们令 \(d=\lfloor\dfrac{A_{i,i}}{A_{j,i}}\rfloor\),我们不断地将第 \(i\) 行乘以 \(-d\) 后倍加到第 \(j\) 行上去并交换 \(i,j\) 两行,直到 \(A_{j,i}=0\) 为止,就像辗转相除法求 \(\gcd\) 那样,这样复杂度看似是 \(n^3\log p\) 的,不过显然每个元素最多被操作 \(\log p\) 次,故复杂度实际上是 \(n^2\log p+n^3\) 的。
模板题代码:
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
while(a[j][i]){
int div=a[i][i]/a[j][i];
for(int k=i;k<=n;k++) a[i][k]=(a[i][k]+1ll*(mod-a[j][k])*div)%mod;
for(int k=i;k<=n;k++) swap(a[i][k],a[j][k]);sgn*=-1;
}
}
} int res=sgn;
for(int i=1;i<=n;i++) res=1ll*res*a[i][i]%mod;
res=(res+mod)%mod;
当然如果题目规定模数是质数,也可以这样写:
int sgn=1;
for(int i=1;i<=n;i++){
int t=i;
for(int j=i+1;j<=n;j++) if(a[j][i]) t=j;
if(t!=i) sgn=-sgn;
for(int j=1;j<=n;j++) swap(a[i][j],a[t][j]);
int iv=qpow(a[i][i],MOD-2);
for(int j=i+1;j<=n;j++){
int mul=1ll*(MOD-a[j][i])*iv%MOD;
for(int k=i;k<n;k++) a[j][k]=(a[j][k]+1ll*a[i][k]*mul)%MOD;
}
} int res=sgn;
for(int i=1;i<=n;i++) res=1ll*res*a[i][i]%MOD;
printf("%d\n",(res+MOD)%MOD);
upd on 2021.6.26:
补充一个小的知识点(虽然 OI 中不一定用得到)
上式被称为范德蒙行列式。
upd on 2021.6.29:似乎这个范德蒙矩阵可以用来解释 IDFT?看来是蒟蒻无知了/kk,等我深入学习 DFT/IDFT 时候再来研究吧/wq