矩阵乘法递推的优化艺术
對于一個線性遞推式,求它第項的值,通常的做法是先構造一個的矩陣,然后在時間內求出。
其實,由于這個矩陣的特殊性,可以將時間優(yōu)化到。接下來我會以一個題目來講解矩陣乘法遞推的優(yōu)化。
?
題目:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1229
?
題意:設,求的值。其中,和
???? 。
?
前言:本題如果用普通的矩陣做法,很明顯會TLE。那么我們要對這個特殊的矩陣進行時間上的優(yōu)化。
?
分析:本題主要可用兩種方法解決,分別是錯位相減和矩陣乘法。先來說說錯位相減的基本做法,把題目描述改一下
???? 以來表示,那么有
?
?????
?
????? 進而得到
?
?????
?
??????接下來,我們重點關注,因為
?
?????
?
??????對于組合系數相同的進行合并得到
?
?????
????? 那么可以看出
?
?????
?
????? 這是一個遞歸式,遞歸出口是當時
?????
?????
?
????? 對于上述遞歸式,為了提高效率,需要進行記憶化,當然這里是針對,當時需要特判。
????? 此時的問題就是典型的自然數冪和問題,關于自然數冪和問題的詳細講解,鏈接如下
?
??????自然數冪和:http://blog.csdn.net/acdreamers/article/details/38929067
?
代碼:
#include <iostream> #include <string.h> #include <stdio.h>using namespace std; typedef long long LL; const int N = 2005; const LL MOD = 1000000007; LL n, r; LL C[N][N]; LL B[N],Inv[N]; LL Tmp[N]; LL ans[N];void Init() {//預處理組合數for(int i=0; i<N; i++){C[i][0] = C[i][i] = 1;if(i == 0) continue;for(int j=1; j<i; j++)C[i][j] = (C[i-1][j] % MOD + C[i-1][j-1] % MOD) % MOD;}//預處理逆元Inv[1] = 1;for(int i=2; i<N; i++)Inv[i] = (MOD - MOD / i) * Inv[MOD % i] % MOD;//預處理伯努利數B[0] = 1;for(int i=1; i<N; i++){LL ans = 0;if(i == N - 1) break;for(int j=0; j<i; j++){ans += C[i+1][j] * B[j];ans %= MOD;}ans *= -Inv[i+1];ans = (ans % MOD + MOD) % MOD;B[i] = ans;} }LL quick_mod(LL a, LL b, LL m) {LL ans = 1;a %= m;while(b){if(b & 1){ans = ans * a % m;b--;}b >>= 1;a = a * a % m;}return ans; }LL Work1(int k) {LL ans = Inv[k+1];LL sum = 0;for(int i=1; i<=k+1; i++){sum += C[k+1][i] * Tmp[i] % MOD * B[k+1-i] % MOD;sum %= MOD;}ans *= sum;ans %= MOD;return ans; }LL Work2(int k) {if(ans[k] != -1) return ans[k];if(k == 0){ans[k] = r * (quick_mod(r, n, MOD) - 1) % MOD * quick_mod(r-1, MOD-2, MOD) % MOD;ans[k] = (ans[k] % MOD + MOD) % MOD;return ans[k];}ans[k] = quick_mod(n+1, k, MOD) * quick_mod(r, n+1, MOD) % MOD * quick_mod(r-1, MOD-2, MOD) % MOD;LL tmp = r * quick_mod(r-1, MOD-2, MOD) % MOD;LL sum = 1;for(int i=k-1; i>=0; i--){sum += C[k][k-i] * Work2(i);sum %= MOD;}ans[k] -= sum * tmp % MOD;ans[k] = (ans[k] % MOD + MOD) % MOD;return ans[k]; }int main() {int T;Init();scanf("%d", &T);while(T--){int k;memset(ans, -1, sizeof(ans));scanf("%I64d %d %I64d", &n, &k, &r);r %= MOD;if(r == 1){n %= MOD;Tmp[0] = 1;for(int i=1; i<N; i++)Tmp[i] = Tmp[i-1] * (n + 1) % MOD;LL ret = Work1(k);printf("%I64d\n", ret);continue;}LL ans = Work2(k);printf("%I64d\n", ans);}return 0; }
已經很完美地解決了上述題目,其實還有一個矩陣乘法的做法,這才是我們今天要討論的重點。以前在HDU上就做過一道與本題差不多的題目,鏈接是:http://acm.hdu.edu.cn/showproblem.php?pid=3483
?
幾乎跟本題差不多,但是HDU3483的數據比較小,普通的矩陣乘法完全沒有壓力,但是同樣的方法卻不能用在此處。
因為本題的比較大,此處行不通。實際上對于遞推式構造的矩陣,由于其特殊性,可以對其進行優(yōu)化,使得時間復
雜度大大降低。接下來,我會用構造矩陣的方法來詳細解析本題。設
?
??????
??????
?
將按二項式展開得到
?
??????
?
那么可以構造如下遞推矩陣
?
??????
?
接下來,可以通過上面的遞推矩陣在時間內求出。但這樣做很明顯會TLE,由于此矩陣的特殊性
--上三角矩陣,可以將時間優(yōu)化到。接下來研究如何將一個遞推矩陣的時間復雜度優(yōu)化到。
?
先來介紹一個很重要的定理----Cayley-Hamilton定理,描述如下
?
?????設是階方陣,是的特征多項式,即,則。
?
用一句話概括就是:方陣的特征多項式是的化零多項式。
?
更多關于Cayley-Hamilton定理的學習請戳這里。
?
本題主要參考這篇文章:《線性遞推關系與矩陣乘法》,如下
?
??????
?
主要用到本文的如下內容
?
???????
?
?????????
?
?
超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生總結
以上是生活随笔為你收集整理的矩阵乘法递推的优化艺术的全部內容,希望文章能夠幫你解決所遇到的問題。