洛谷P7112 行列式求值
行列式求值
這是一個讓你掉頭髮的模板題
行列式的定義
行列式 (\(\texttt{Determinant}\)) 是一個函式定義,取值是一個標量。
對一個 \(n\times n\) 的矩陣 \(A\)(\(n\) 階方陣),其 \(n\) 階行列式寫作 \(\det(A)\) 或者 \(|A|\),定義為:
\[\det(A)=|A|=\sum_p(-1)^{\tau(p)}\prod_{i=1}^n a_{i,p_i} \]\(p\) 表示一個排列,所有可能的 \(p\) 則是 \(1\) 到 \(n\) 這 \(n\) 個數的全排列。 \(\tau(p)\) 表示一個排列 \(p\)逆序對個數
-
2階矩陣的行列式:
\[\begin{vmatrix}a & b \\c & d\end{vmatrix}=ad-bc \] -
3階矩陣的行列式:
\[\begin{vmatrix}a_{11} & a_{12} & a_{13} \\a_{21} & a_{22} &a_{23} \\a_{31} & a_{32} & a_{33}\end{vmatrix}=a_{11} a_{22} a_{33} + a_{12} a_{23} a_{31} + a_{13} a_{21} a_{32} - a_{13} a_{22} a_{31} - a_{11} a_{23} a_{32} - a_{12}a_{21}a_{33} \]
我們今天的問題,僅限於如何把行列式的值求出來
前置知識
\(\tau(p)\)性質
我們發現 \(\tau(p)\) 的奇偶性對行列式求值起到了很大的影響,所以我們需要了解排列的奇偶性相關。
- 我們約定:如果 \(\tau(p)\) 為奇數,則 \(p\) 為一個奇排列,否則是一個偶排列;
- 對於排列 \(p\) 我們交換其中的 \(2\) 個元素,其餘元素不邊,會得到一個新的排列,這種操作叫 對換 ;
- 一次對換會改變排列的奇偶性(這是我們需要用到的定理)
- 證明如下:
- 設排列p(1到m)中,需要交換的兩個元素分別為\(p_l和p_r\),令\(n=r-l+1\)
- 顯然,交換\(p_l和p_r\)不會改變\(p_l和p_r\)與\([1,l-1]和[r+1,m]\)中的元素組成逆序對,那麼我們只需要考慮[l,r]中產生的影響即可
- 我們對\(p_l,p_{l+1},p_{l+2}……p_{r}\)進行離散化(把這個子排列變成一個1到n的排列),例如:\(p[l:r]=[2,5,4]則p'[l:r]=[1,3,2]\),其中p[l]在離散化後的排列中,大小為x,p[r]大小為y
- 我們發現,交換前,子序列中除\(p_l\)外,與\(p_l\)能構成\(n-x\)個逆序對,除\(p_r\)外,與\(p_r\)能構成\(y-1\)個逆序對,考慮x和y產生逆序對的情況後,加起來則是:\((n-x)+(y-1)-[x>y]\)
- 交換後,子序列中除\(p_l\)外,與\(p_l\)能構成\(x-1\)個逆序對,除\(p_r\)外,與\(p_r\)能構成\(n-y\)個逆序對,考慮x和y產生逆序對的情況後,加起來則是:\((x-1)+(n-y)-[y>x]\)
- 交換前後,相差的逆序對個數為\((n-x)+(y-1)-[x>y]-(x-1)-(n-y)+[y>x]=2n-2x-2y+2±1\)對,顯然為奇數(±1產生的原因:\([x>y]和[y>x]\)中間有且僅有一個會被滿足,所以\([y>x]-[x>y]\)的值為±1)
行列式性質1:
交換對應矩陣的 \(2\) 行(列),行列式的值取反
\(\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_{k,1} &a_{k,2} &\cdots &a_{k,n}\\\ a_{k+1,1} &a_{k+1,2} &\cdots &a_{k+1,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_{k+1,1} &a_{k+1,2} &\cdots &a_{k+1,n}\\\ a_{k,1} &a_{k,2} &\cdots &a_{k,n}\\\ \vdots &\vdots &\ddots &\vdots\\\ a_{n,1}&a_{n,2}&\cdots&a_{n,n}\\\ \end{vmatrix}\)
(注意右邊的矩陣,只有中間那兩行是換了位置的,其餘都沒換位置)
證明如下:
設左邊的行列式為A,右邊為B求行列式的式子長這樣:
\[\det(A)=|A|=\sum_p(-1)^{\tau(p)}\prod_{i=1}^n a_{i,p_i} \]我們對上面的式子做一點細微的修改,把它改成求\(det(B)\)
我們能不能構造一個排列q,使得排列q是利用某種神祕力量,從排列p轉化而來,這樣就能用a的值來代替b了?
就像這樣:
\[\det(B)=\sum_p(-1)^{\tau(p)}\prod_{i=1}^n b_{i,p_i} \ ?\ \sum_q(-1)^{\tau(q)}\prod_{i=1}^n a_{i,q_i} \]當然可以。p和q的區別,僅在於第k位和第k+1位被換了位,這樣就有\(b_{i,p_i}=a_{i,q_i}\)了!代價是\(\tau(p)=-\tau(q)\)
則有:
\[\det(B)=\sum_p(-1)^{\tau(p)}\prod_{i=1}^n b_{i,p_i} = \sum_q(-1)^{\tau(p)-1}\prod_{i=1}^n a_{i,p_i}=-det(A) \]行列式性質2:
行列式的行(列)所有元素等比例變化,則行列式的值也等比例變化:
- $\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\\ k\times a_{i,1} &k\times a_{i,2} &\cdots &k\times a_{i,n}\\ \vdots &\vdots &\ddots &\vdots\\ a_{n,1}&a_{n,2}&\cdots&a_{n,n}\\ \end{vmatrix} =k\times \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} $
我們用乘法分配律,即可證明這個性質
行列式性質3:
如果行列式對應矩陣 \(A\) 中有一行(列),是對應 \(2\) 個矩陣 \(B,C\) 中分別的 \(2\) 行(列)所有元素之和。那麼有 \(\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\\ b_{i,1}+c_{i,1} &b_{i,2}+c_{i,2} &\cdots &b_{i,n}+c_{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_{i,1} &b_{i,2} &\cdots &b_{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\\ c_{i,1} &c_{i,2} &\cdots &c_{i,n}\\ \vdots &\vdots &\ddots &\vdots\\ a_{n,1}&a_{n,2}&\cdots&a_{n,n}\\ \end{vmatrix} $
我們可以對每個\(b_i,?+c_i,\)進行乘法分配律,來完成證明
行列式性質4:
-
由性質1和性質2可以推出:
-
如果一個矩陣存在兩行(列)成比例則 \(\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\\ k\times a_{i,1} &k\times a_{i,2} &\cdots &k\times 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\\ k\times a_{i,1} &k\times a_{i,2} &\cdots &k\times a_{i,n}\\ \vdots &\vdots &\ddots &\vdots\\ a_{n,1}&a_{n,2}&\cdots&a_{n,n}\\ \end{vmatrix}=k\times \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_{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} $
-
設右邊的矩陣為\(A'\),由於存在兩行相同,我們交換兩行後可以得到\(-A'\),且\(-|A'|=|-A'|\)
-
得\(|A'|=0,|A|=0\times |A'|=0\)
行列式性質5:
- 把一個矩陣的一行(列)的值全部乘一個常數加到另一行(列)上,行列式值不變。\((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\\ a_{j,1}+k\times a_{i,1} &a_{j,2}+k\times a_{i,2} &\cdots &a_{j,2}+k\times 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,2}\\ \vdots &\vdots &\ddots &\vdots\\ a_{n,1}&a_{n,2}&\cdots&a_{n,n}\\ \end{vmatrix} $
證明也很簡單,根據 \((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\\ a_{j,1}+k\times a_{i,1} &a_{j,2}+k\times a_{i,2} &\cdots &a_{j,2}+k\times 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,2}\\ \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\\ k\times a_{i,1} &k\times a_{i,2} &\cdots &k\times a_{i,n}\\ \vdots &\vdots &\ddots &\vdots\\ a_{n,1}&a_{n,2}&\cdots&a_{n,n}\\ \end{vmatrix} $
- $\because $行列式性質4
- $\therefore \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}+k\times a_{i,1} &a_{j,2}+k\times a_{i,2} &\cdots &a_{j,2}+k\times 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,2}\\ \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}+k\times a_{i,1} &a_{j,2}+k\times a_{i,2} &\cdots &a_{j,2}+k\times 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,2}\\ \vdots &\vdots &\ddots &\vdots\\ a_{n,1}&a_{n,2}&\cdots&a_{n,n}\\ \end{vmatrix} $
行列式性質6:
如圖所示:這是一個三角行列式
$\begin{vmatrix} \color{orange}a_{1,1} & \color{green}a_{1,2} &
\color{blue}a_{1,3} & \color{red}\cdots &\color{red}a_{1,n-1} &a_{1,n}\\ 0 &
\color{green}a_{2,2} & \color{blue}a_{2,3} & \color{red}\cdots
&\color{red}a_{2,n-1} &a_{2,n}\\ 0 &0 &\color{blue} a_{3,3} &\color{red}
\cdots &\color{red}a_{3,n-1} &a_{3,n}\\ \color{red}\vdots & \color{red}\vdots
& \color{red}\vdots & \color{red}\ddots &\color{red} \vdots &\vdots\\ 0 &0 &
0 & \color{red}\cdots &\color{red}a_{n-1,n-1} &a_{n,n-1}\\ 0 & 0 & 0 & \cdots
&0 &a_{n,n}\\ \end{vmatrix} $
三角行列式的值非常好求: \(|A|=\displaystyle\prod_{i=1}^na_{i,i}\)
這一條式子很好證明:
我們考慮一個情況,當一個矩陣任意一個位置出現 \(0\),其對行列式的影響非常大。
因為我們考慮公式中 \(\displaystyle\prod_{i=1}^n a_{i,p_i}\) 一項,一旦選到 \(0\) 整個 \(p\) 在
\(\displaystyle \sum_p\) 中就沒有貢獻了。
在求行列式值時,序列p不指向對角線上元素時,是不是一定會選到0呢?
行列式求值
下面開始進入正題
我會暴力!
直接根據定義計算,行列式求值是 \(\Theta(n\times n!)\) 的。
有了上面七個性質,我們有辦法加快運算嗎?
消元
我們考慮一個情況,當一個矩陣任意一個位置出現 \(0\),其對行列式的影響非常大。
因為我們考慮公式中 \(\displaystyle\prod_{i=1}^n a_{i,p_i}\) 一項,一旦選到 \(0\) 整個 \(p\) 在
\(\displaystyle \sum_p\) 中就沒有貢獻了。
下面進入大膽猜想:
我們能不能對原行列式A進行一系列的變換,使得它變成一個三角行列式,像下面這樣?
\(A=\begin{bmatrix} a_{1,1} & a_{1,2} & a_{1,3} & \cdots &a_{1,n}\\\ a_{2,1} & a_{2,2} & a_{2,3} & \cdots &a_{2,n}\\\ a_{3,1} & a_{3,2} & a_{3,3} & \cdots &a_{3,n}\\\ \vdots & \vdots & \vdots & \ddots & \vdots\\\ a_{n,1} & a_{n,2} & a_{n,3} & \cdots &a_{n,n}\\\ \end{bmatrix}\) \(\Rightarrow\) \(\begin{bmatrix} a’_{1,1} & a‘_{1,2} & a’_{1,3} & \cdots &a‘_{1,n}\\\ 0 & a’_{2,2} & a‘_{2,3} & \cdots &a_{2,n}\\\ 0 & 0 & a’_{3,3} & \cdots &a‘_{3,n}\\\ \vdots & \vdots & \vdots & \ddots & \vdots\\\ 0 & 0 & 0 & \cdots &a’_{n,n}\\\ \end{bmatrix}\)
這個三角行列式,怎麼和高斯消元,完成加減消元時的矩陣很像?
我們能不能像高斯消元中加減消元一樣,利用行列式第\(i\)行的資訊,把第\(i+1\)到\(n\)行中\(a[][i]\)變為0
當然可以!
程式碼長這樣:
double sol()
{
double res=1;
for(int i=1;i<=n;i++)
{
for(int j=i+1;j<=n;++j)
{
double div=a[j][i]/a[i][i];
for(int k=i;k<=n;++k)
{
a[j][k]=(a[j][k]-div*a[i][k]);
}
}
}
for(int i=1;i<=n;i++) res*=a[i][i];
return res;
}
但是,此題要求你取模,模的數甚至不是質數?還乘不了逆元?
出現了一點小問題
我們可以把除or乘逆元,換成輾轉相除?像這樣:
\[\begin{vmatrix}18 & 5 & 1 \\12 & 2 &3 \\4& 2 & 1\end{vmatrix}=-\begin{vmatrix}12 & 2 &3 \\18 & 5 & 1 \\4& 2 & 1\end{vmatrix}=-\begin{vmatrix}12 & 2 &3 \\6 & 3 & -2 \\4& 2 & 1\end{vmatrix}=\begin{vmatrix}6 & 3 & -2 \\12 & 2 &3 \\4& 2 & 1\end{vmatrix}=\begin{vmatrix}6 & 3 & -2 \\0 & -4 &-1 \\4& 2 & 1\end{vmatrix} \]我們成功在\(a[2][1]\)處製造了一個0出來!!
通過這樣的方式,我們就可以在p不為質數的時候,把這個行列式安全地化為三角行列式
消元操作是 \(\Theta(n^3)\) 的,輾轉相除法是 \(\Theta(\log p)\)的,因為輾轉相除和消元每次必然使得數變小,勢能只會減少,所以這個是均攤到 \(\Theta(n^2)\) 的,最終複雜度為 \(\Theta(n^2\log n+n^3)\)。
程式碼
#include<bits/stdc++.h>
#define INL inline
#define ll long long
using namespace std;
const int N=605;
int n,a[N][N],MOD;
INL int read()
{
int x=0,w=1;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')w=-1,ch=getchar();
while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+ch-48,ch=getchar();
return x*w;
}
INL int sol()
{
int res=1,w=1;
for(int i=1;i<=n;i++)
{
for(int j=i+1;j<=n;++j)
{
while(a[i][i])
{
int div=a[j][i]/a[i][i];
for(int k=i;k<=n;++k)
{
a[j][k]=(a[j][k]-1ll*div*a[i][k]%MOD+MOD)%MOD;
}
swap(a[i],a[j]);w=-w;
}//對第 i 行和第 j 行做輾轉相減。
swap(a[i],a[j]);w=-w;
}
}
for(int i=1;i<=n;i++)res=1ll*a[i][i]*res%MOD;
res=1ll*w*res;
return (res+MOD)%MOD;
}
int main()
{
n=read(),MOD=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
a[i][j]=read();
int ans=sol();printf("%d\n",ans);
return 0;
}