前言
因為博主太菜了所以需要寫筆記來加深理解。
感謝隊爺 cly 對我的耐心指導。
Part 1 向量
Part 2 矩陣乘法
矩陣其實可以看成若干向量。
矩陣相乘的定義我就不講了,這個不知道的自己百度一下。
關於這部分,引入一些奇怪的知識(說奇怪是因為我目前沒有用到過):
-
可以行拆分和列拆分進行運算,實質也是分塊矩陣。具體的,進行運算的兩段左邊進行行拆分,右邊進行列拆分。
-
可以拆分成分塊矩陣。(配合一些亂七八糟的東西能達到 \(\operatorname {O}(n^{\omega})\) 求行列式,當然我覺得現階段沒必要,也掌握不了)
第二種理解方式
hehezhou 給了我又一種理解矩陣乘法的方式。
矩陣中的元素 \(A_{i,j}\) 表示從點 \(i\) 到點 \(j\) 的方案數。
若是從這個角度的話就可以快速地理解一些東西了。
Part 3 矩陣轉化
如何把一個矩陣轉化成我想要的樣子呢?
這里我不知道怎么寫比較好的引子,就直接上正題了吧。
在講這塊之前,需要一些前置知識:
矩陣的初等變換
矩陣的初等變換有三種:
\(1.\) 交換某兩行(注意對應到矩陣的乘法中,需要左乘初等變換矩陣,若右乘即為交換兩列)。
\(2.\) 將某一行乘上一個非零實數 \(k\)。
\(3.\) 將某一行的 \(k\) 倍(向量內每個元素都變成原來的 \(k\) 倍的意思)加到另一行上。
那么應該如何實現這三種操作呢?
單位矩陣
單位矩陣是一個 只有主對角線上的元素為一,其它都為零 的 \(n\times n\) 的矩陣,擁有 任何矩陣乘上單位矩陣都是自身 的良好性質,可以類比為普通乘法中的 \(1\)。
初等矩陣
那么若是我們對單位矩陣進行上述的初等變換,然后再將我們想進行操作的矩陣乘上這個得到的東西,是否就可以得到我們想要的結果?
小編也很驚訝,但事實就是這樣。
你可以從定義或者上面描述的乘法的角度去理解。
對單位矩陣進行一次初等變換得到的東西,稱為初等矩陣。
你會發現這個東西妙得很,可以做高斯消元,因為高斯消元需要的操作無非也是這幾種。
並且你會發現,需要的是左乘初等矩陣,因為右乘會對列進行操作。
若是一個矩陣可以進行若干次初等變換變成單位矩陣,那么便稱之為是可逆的。
但是具體的代碼實現里面,並不需要真正去構建這種矩陣來轉換,更多的是用於一些推導和證明。因為如果真的要實現那三種變換,直接按照定義去實現就好了。
Part 4 矩陣的逆
定義一個矩陣 \(A\) 的逆 \(B\),滿足 \(AB=BA=E\),其中 \(E\) 表示單位矩陣。
具體的求法,我們可以將 \(E\) 拆分為 \(A\) 和若干個初等矩陣的乘積:\(x_1 x_2 \cdots A\),也就是說,\(A\) 可經過若干次初等變換得到 \(E\)。對於上面那個等式,我們左右同時左乘上這若干個初等矩陣,就得到了 \(EB=x_1 x_2 \cdots E\),那么 \(B=x_1 x_2 \cdots E\)。
那么如果不滿足那個拆分的 \(A\) 呢?答案是 \(A\) 無逆,這點在之后的行列式求值也可以相聯系。
Part 5 高斯消元
這個我感覺沒有什么特別好講的,利用前面的初等變換,進行平時解方程組的操作,不斷消去未知數。
這里引入一個 增廣矩陣 的概念,具體的,將未知數系數表示成一個 系數矩陣 \(A\),常數項單獨作為一個矩陣(也可以叫做向量)\(x\),那么 增廣矩陣 \(B=(A|x)\),是這樣一個表示形式。這個定義會在后面用到。
那么 \(B\) 也是一樣可以通過一系列變換變成階梯型矩陣的。
練習
矩陣求逆
高斯消元
Part 6 行列式
式子我就不寫了,網上都有。
朴素地求行列式的復雜度是 \(\operatorname O(n!(n \log+n))\)(大概)
反正也不會真有人去暴力做這個東西。
利用行列式的一些性質來進行求解:
\(1.\) 交換某兩行。行列式取負。
\(2.\) 將某一行乘上一個非零實數 \(k\)。行列式乘上 \(k\)。
\(3.\) 將某一行的 \(k\) 倍(向量內每個元素都變成原來的 \(k\) 倍的意思)加到另一行上。行列式不變。
\(4.\) 一個矩陣若是有逆,則其行列式為逆矩陣的逆元(若是取模意義下的話),否則行列式為 \(0\)。
那么就是一樣去做高斯消元的過程求逆矩陣(當然實際並不用求出這個逆),然后對行列式進行計算。
這里的計算部分有一種很巧妙的寫法:將 \(A\) 消成上三角矩陣以后,將對角線元素相乘即為答案。至於為什么,可以自己推導一下,很有意思的。
以及,在這個過程中,如果說當前求行列式的矩陣不可逆,那么必然會在若干步初等變換后,出現某個對角線上的元素為 \(0\) 的情況,那么顯然矩陣的行列式為 \(0\)。
也就是說:矩陣有逆 \(\Leftrightarrow\) 矩陣行列式不為 \(0\)。反之也是成立的,這樣可以使得行列式與矩陣求逆聯系在一起。
最小生成樹計數
rt,如何計算最小生成樹的方案數呢?
構造一個基爾霍夫矩陣,然后求出去掉最后一行和最后一列以后的行列式。
注:基爾霍夫矩陣中 \(A_{i,i}\) 表示點 \(i\) 的度數,\(A_{i,j},i!=j\) 表示鄰接矩陣中 \(A_{i,j}\) 的相反數。(連邊數取反)
練習
模板題
小 Z 的房間:
這題因為是對非質數取模,所以需要進行輾轉相除。輾轉相除的原理導致其跑完一遍只能將其消成上三角矩陣。然后這個過程中行列式只會有正負的變化,那么所有的 \(1\) 操作對行列式的貢獻在上三角矩陣中就已經可以直接相乘求得了。
本身是需要將其 \(\times \frac{1}{c}\),但因為最后還要倒過來,所以就直接乘 \(c\) 計算就好了。
同時提醒我們,因為行列式跑的是最小生成樹的方案數,所以若是塞進去無用的點會導致方案數變為 \(0\)。
輾轉相除不得往回消。
[SHOI2016]黑暗前的幻想鄉
也可以算作是板題,不過套了個簡單容斥。
[JSOI2008]最小生成樹計數
如何證明:按邊權排序分層后,相同權值的邊選取可行的 \(k\) 條對后面的層無影響,也就是無后效性。若是正確,則可以應用乘法原理來計算方案數,因為層層之間實際上獨立。
在 kruskal 執行的過程中,對於 \(x\) 條相同權值的邊,從中選取 \(k\) 條邊保證選取后圖為森林,這樣形成的所有聯通塊的內部信息(只考慮有哪些節點,連接方案無所謂)是相同的。
考慮反證法,若不相同,則一定存在一條當前權值的邊連接某兩個聯通塊,使得這兩者合並。
雙倍經驗 (甚至連代碼都不用改,省選直接放兩年前原題可還行)
對於這種分層的需要注意:
-
初始跑一遍判是否有解。
-
需要將除本層以外應加入的邊加入后再去做。
Part 7 矩陣的秩
簡單來說,秩就是:矩陣內部的極大 線性獨立 向量的數目,自然有行列之分。
線性獨立的一些向量,如果刪去了某一個,那么它就不能被剩下的向量給表示出來。
更嚴謹的定義可以去網絡上搜索,這里不過於詳細地介紹。因為實際用處不大
現階段,你大概只需要知道:秩就是高消出來的階梯形矩陣的主元個數。
定義 \(r(A)\) 表示矩陣 \(A\) 的秩。
練習
POJ1830 開關問題
按照每個開關的效果構造出對應的向量,將它們轉化為若干線性無關的向量,然后根據題意判斷即可。
線性方程組
這里就可以用到前面那個定義了。對於 \(B=(A|x)\),分討一下(已經通過高消轉成線性無關的若干向量):
-
無解的判斷是 \(r(B)>r(A)\),也就是某向量屬於 \(A\) 的部分都為 \(0\),屬於 \(x\) 的卻非零。
-
有解且 \(r(A)=n\),那么有唯一解。
-
有解且 \(r(A)<n\),那么有無窮多解。
Part 8 線性基
前置知識
線性基指的是能夠用 向量集合中若干向量通過線性運算得到 表示出來的向量集合。
更公式化地,可以描述為:對於線性無關的 \(n\) 個向量 \(x_1,x_2\cdots x_n\),所有可以表示為 \(a_1x_1+a_2x_2+\cdots a_nx_n\) 的向量組成的集合,就是一個線性基。
高消不會改變線性基
線性基可以用若干個線性無關的向量來描述,而高消的過程,實質上就是將這些線性無關向量求出的過程。
關於代碼實現
這里推薦一種陽間的寫法:
LL val[53];
inline void insert(LL x){for(int i=50;i>=0;i--)if((x>>i)>0){if(!val[i]){val[i]=x;break;}x^=val[i];}return;}
是支持動態插入維護的線性基。
練習
模板題
通過高消得到的階梯型矩陣,滿足每個主元列上,除了主元以外其他元素都為 \(0\)。
根據這個性質,我們就可以貪心選取了。
CF388D
這道題考察大家對於線性基知識的掌握程度,然后用這些知識寫出轉移方程式。
\(\texttt{2020-11-06 擴展題練習}\)
紀念一下第一次在 VJ 上拿 Rank 1。
這里面的題目都還不錯,除了毒瘤高精 E。
下面五道是我覺得非常妙的,可以從中學到不少技巧性的東西。比如說如何構建轉移矩陣,以及矩陣和一些算法的經典組合運用。
禁忌
經典多合一。
傑傑的女性朋友
考驗矩陣運算性質的運用。
Fibonacci Strings
兩個套路結合起來的題。
Axel and Marston in Bitland
算是這之中比較簡單的一道。
向量內積
其實和線性代數關系並不是非常大,是道妙妙亂搞。