摘要
本文主要講解矩陣乘法和矩陣快速冪。內容不難,都是定理,重點是矩陣乘法的應用。
藍橋杯知識點彙總:
https://blog.csdn.net/GD_ONE/article/details/104061907
矩陣
數學上,一個的矩陣是一個由行(row)n列(column)元素排列成的矩形陣列。矩陣裏的元素可以是數字、符號或數學式。以下是一個由6個數字元素構成的2行3列的矩陣:
-------引用自維基百科。
知道了矩陣是什麼後,看看什麼是矩陣乘法。
矩陣乘法
數學中,矩陣乘法(英語:matrix multiplication)是一種根據兩個矩陣得到第三個矩陣的二元運算,第三個矩陣即前兩者的乘積,稱爲矩陣積(英語:matrix product)。設是的矩陣,是的矩陣,則它們的矩陣積是的矩陣。中每一行的個元素都與中對應列的個元素對應相乘,這些乘積的和就是中的一個元素。
-------引用自維基百科。
直接看圖:
矩陣乘法的代碼實現就是直接模擬乘法過程,所以沒什麼好說的,直接給出代碼:
public static void mut_mul(long[][] a, long[][] b, long[][] c){ // c = a * b
long[][] t = {{0, 0}, {0, 0}}; // 中間數組
for(int i = 0; i < 2; i++)
for(int j = 0; j < 2; j++)
for(int k = 0; k < 2; k++)
t[i][j] = (t[i][j] + (a[i][k]*b[k][j]) % mod)%mod;
for(int i = 0; i < 2; i++) c[i] = Arrays.copyOf(t[i], 2);
}
矩陣快速冪
矩陣快速冪和普通快速冪思路完全一樣,實現代碼的時候將整數乘法變爲矩陣乘法就可以了。
代碼:
public static void mut_mul(long[][] a, long[][] b, long[][] c){
long[][] t = {{0, 0}, {0, 0}};
for(int i = 0; i < 2; i++)
for(int j = 0; j < 2; j++)
for(int k = 0; k < 2; k++)
t[i][j] = (t[i][j] + (a[i][k]*b[k][j]) % mod)%mod;
for(int i = 0; i < 2; i++) c[i] = Arrays.copyOf(t[i], 2);
}
public static void qmi(long[][] a, long b, long[][] c){// a = a * c^b
while(b != 0){
if((b & 1) == 1){
mut_mul(a, c, a);
}
b >>= 1;
mut_mul(c, c, c);
}
}
以上就是矩陣快速冪的代碼了。
矩陣乘法的應用
矩陣是數學家求解線性方程組的過程中發明的,對於:
將未知數的係數歸爲一個矩陣,將未知數歸爲一個矩陣,將結果歸爲一個矩陣得到:
用第一個矩陣乘以第二個矩陣,就可以得到原來的線性方程組。
所以矩陣相乘更像是一種函數,讓第一個矩陣通過某種映射關係,轉化到另一個矩陣。
對於斐波那契數列數列:
轉化爲關係式:
從第三項開始,每一項都是前兩項的和,我們能否用矩陣相乘來表示這個關係呢?
設矩陣A爲:
設矩陣C爲:
矩陣A怎麼變爲矩陣C呢?
矩陣C的第一個元素爲
所以我們構造出一個關係矩陣:
於是可以將 轉化爲:
對於斐波那契數列來說,關係矩陣是不變的,所以如果要用上式來求斐波那契數列的第的話,我們可以這樣做:
即用矩陣乘以關係矩陣n-1次。
這樣做的時間複雜度反而比用原本的關係式遞推求更高了,但是我們可以對其進行優化,那就是用矩陣快速冪來算關係矩陣的(n-1)次方。這樣時間複雜度就降到了級別。
一般要用矩陣乘法求解的問題都要構造一個關係矩陣,能否正確的構造出關係矩陣,就是解題的關鍵了。
例題:
問題描述
在一個奇怪的星球上駐紮着兩個蟲羣A和B,它們用奇怪的方式繁殖着,在t+1時刻A蟲羣的數量等於t時刻A蟲羣和B蟲羣數量之和,t+1時刻B蟲羣的數量等於t時刻A蟲羣的數量。由於星際空間的時間維度很廣闊,所以t可能很大。OverMind 想知道在t時刻A蟲羣的數量對 p = 1,000,000,007.取餘數的結果。當t=1時 A種羣和B種羣的數量均爲1。
輸入格式
測試數據包含一個整數t,代表繁殖的時間。
輸出格式
輸出一行,包含一個整數,表示對p取餘數的結果
樣例輸入
10
樣例輸出
89
樣例輸入
65536
樣例輸出
462302286
數據規模和約定
對於50%的數據 t<=10^9
對於70%的數據 t<=10^15
對於100%的數據 t<=10^18
題解:
正解就是構造一個關係矩陣,然後用求斐波那契數列第n項的方式求解答案就可以了,先不看下面的題解,自己嘗試構造一下吧。
題目說:在。
我們設矩陣A爲, 矩陣C爲
則關係矩陣爲:
得到關係矩陣後就直接套用矩陣乘法和矩陣快速冪模板就可以了,
AC代碼:
因爲最大數據是,注意用long,還有一點是,因爲數據太大了,矩陣乘法中,加法加完也要取模。
import java.io.*;
import java.util.*;
public class Main {
static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
static BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));
static final int mod = 1000000007;
public static void mut_mul(long[][] a, long[][] b, long[][] c){
long[][] t = {{0, 0}, {0, 0}}; // 中間數組
for(int i = 0; i < 2; i++)
for(int j = 0; j < 2; j++)
for(int k = 0; k < 2; k++)
t[i][j] = (t[i][j] + (a[i][k]*b[k][j]) % mod)%mod;
for(int i = 0; i < 2; i++) c[i] = Arrays.copyOf(t[i], 2);
}
public static void qmi(long[][] a, long b, long[][] c){// a = a * c^b
while(b != 0){
if((b & 1) == 1){
mut_mul(a, c, a);
}
b >>= 1;
mut_mul(c, c, c);
}
}
public static void main(String[] args) throws NumberFormatException, IOException{
long n;
n = Long.valueOf(in.readLine());
long[][] a = {{1,1}, {0,0}}; //初始A和B都是1, 然後因爲矩陣乘法都是二維數組,所以這裏也將其寫作二維數組。
long[][] c = {{1, 1}, {1, 0}};// 關係數組
qmi(a, n-1, c);
out.write(a[0][0] + "\n");
out.flush();
}
}