1. 程式人生 > 其它 >洛谷P7112 行列式求值

洛谷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} \]
\[\begin{vmatrix}18 & 5 & 1 \\12 & 2 &3 \\4& 2 & 1\end{vmatrix} \]

我們今天的問題,僅限於如何把行列式的值求出來

前置知識

\(\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 $

行列式性質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;
}