本文介紹線性代數中乙個非常重要的內容——矩陣(matrix)的乙個重要性質:矩陣加速遞推同時本文已經更新至:矩陣(matrix)系統介紹篇斐波那契數列(fibonacci sequence)大家應該都非常的熟悉了。在斐波那契數列當中,\(f_1 = f_2 = 1\),\(f_i = f_ + f_(i \geq 3)\)。
如果有一道題目讓你求斐波那契數列第 \(n\) 項的值,最簡單的方法莫過於直接遞推了。但是如果 \(n\) 的範圍達到了 \(10^\) 級別,遞推就不行了,穩 tle。考慮矩陣加速遞推。
設 \(fib(n)\) 表示乙個 \(1 \times 2\) 的矩陣 \(\left[ \beginf_n & f_ \end\right]\)。我們希望根據 \(fib(n-1)=\left[ \beginf_ & f_ \end\right]\) 推出 \(fib(n)\)。
試推導乙個矩陣 \(\text\),使 \(fib(n-1) \times \text = fib(n)\),即 \(\left[\beginf_ & f_\end\right] \times \text = \left[ \beginf_n & f_ \end\right]\)。
怎麼推呢?因為 \(f_n=f_+f_\),所以 \(\text\) 矩陣第一列應該是 \(\left[\begin 1 \\ 1 \end\right]\),這樣在進行矩陣乘法運算的時候才能令 \(f_\) 與 \(f_\) 相加,從而得出 \(f_n\)。同理,為了得出 \(f_\),矩陣 \(\text\) 的第二列應該為 \(\left[\begin 1 \\ 0 \end\right]\)。
綜上所述:\(\text = \left[\begin 1 & 1 \\ 1 & 0 \end\right]\) 原式化為 \(\left[\beginf_ & f_\end\right] \times \left[\begin 1 & 1 \\ 1 & 0 \end\right] = \left[ \beginf_n & f_ \end\right]\)
轉化為**,應該怎麼求呢?
定義初始矩陣 \(\text = \left[\beginf_2 & f_1\end\right] = \left[\begin1 & 1\end\right], \text = \left[\begin 1 & 1 \\ 1 & 0 \end\right]\)。那麼,\(f_n\) 就等於 \(\text \times \text^\) 這個矩陣的第一行第一列元素,也就是 \(\left[\begin1 & 1\end\right] \times \left[\begin 1 & 1 \\ 1 & 0 \end\right]^\) 的第一行第一列元素。
注意,矩陣乘法不滿**換律,所以一定不能寫成 \(\left[\begin 1 & 1 \\ 1 & 0 \end\right]^ \times \left[\begin1 & 1\end\right]\) 的第一行第一列元素。另外,對於 \(n \leq 2\) 的情況,直接輸出 \(1\) 即可,不需要執行矩陣快速冪。
為什麼要乘上 \(\text\) 矩陣的 \(n-2\) 次方而不是 \(n\) 次方呢?因為 \(f_1, f_2\) 是不需要進行矩陣乘法就能求的。也就是說,如果只進行一次乘法,就已經求出 \(f_3\) 了。如果還不是很理解為什麼冪是 \(n-2\),建議手算一下。
下面是求斐波那契數列第 \(n\) 項對 \(10^9+7\) 取模的示例**(核心部分)。
const int mod = 1000000007;
struct matrix
matrix operator*(const matrix &b) const
} ans, base;
void init()
void qpow(int b)
}int main()
這是乙個稍微複雜一些的例子。
\[f_ = f_ = 0\\
f_ = 7f_+6f_+5n+4\times 3^n
\]我們發現,\(f_n\) 和 \(f_, f_, n\) 有關,於是考慮構造乙個矩陣描述狀態。
但是發現如果矩陣僅有這三個元素 \(\beginf_n& f_& n\end\) 是難以構造出轉移方程的,因為乘方運算和 \(+1\) 無法用矩陣描述。
於是考慮構造乙個更大的矩陣。
\[\beginf_n& f_& n& 3^n & 1\end
\]我們希望構造乙個遞推矩陣可以轉移到
\[\begin
f_& f_& n+1& 3^ & 1
\end
\]轉移矩陣即為
\[\begin
7 & 1 & 0 & 0 & 0\\
6 & 0 & 0 & 0 & 0\\
5 & 0 & 1 & 0 & 0\\
12 & 0 & 0 & 3 & 0\\
5 & 0 & 1 & 0 & 1
\end
\]有了上面的基礎能很快做出 又見斐波那契
圖源來自網路上一位博主這個相比普通的斐波那契數列多了後面四項,看一眼資料範圍,使用普通的 \(o(n)\) 的演算法肯定會超時
因此這裡需要使用矩陣快速冪(斐波那契數列的項數n一旦過大,就要考慮快速冪,普通演算法時間空間都開銷太大)。
使用矩陣快速冪的乙個關鍵問題就是矩陣遞推式。
然後通過計算等價替換可得出該矩陣a:
下面只需要把普通斐波那契數列的構造由2*2的矩陣換為6*6的即可。
using ll = long long;
const int mod = 1e9 + 7;
const int n = 6;
ll tmp[n][n], res[n][n];
ll n;
void mul(ll a[n], ll b[n])
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j)a[i][j] = tmp[i][j];
}void pow(ll a[n])
}void solve() ;
pow(ans);
ll sum = 0;
ll x[n] = ;
for (int i = 0; i < n; ++i)
cout << sum << "\n";
}
矩陣加速遞推
關於矩陣加速數列遞推 給定乙個遞推數列 f i a 1 f i 1 a 2 f i 2 a k f i k 我們普通計算的話肯定是逐個計算,複雜度較大。我們可以用矩陣表示 left begin f i f i 1 f i k end right 為了遞推出 f n 我們需要找到乙個係數矩陣 a 使得...
模板 矩陣加速(數列)(矩陣加速遞推)
a 1 a 2 a 3 1 a x a x 3 a x 1 x 3 求a數列的第n項對1000000007 10 9 7 取餘的值。輸入格式 第一行乙個整數t,表示詢問個數。以下t行,每行乙個正整數n。輸出格式 每行輸出乙個非負整數表示答案。矩陣加速裸題 和我的前一篇基本一模一樣 只不過改變了要乘的...
矩陣加速遞推 入門指南
首先是乙個例題,輸入n和m,問用1x2的方塊填滿4xn的格仔共有多少種方案數,答案對m取模。分析問題可以找出所有狀態,用乙個1x4的位表示一行的方塊情況,0表示暫時為空,1表示恰好填入方塊。雖然4個二進位制位共有16中可能,但是合法的方案數實際只有6中,0000 0011 0110 1001 110...