日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

矩阵乘法优化递归式

發(fā)布時間:2024/1/17 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 矩阵乘法优化递归式 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

序:

在OI比賽中,很多情況下我們可以能通過打表(找規(guī)律)或者某些方式發(fā)現(xiàn)一個遞歸式。
例如:f(n) = f(n - 1)+f(n - 2),(斐波那契數(shù)列)。

通常情況下,我們計算f(n)的時間復雜度就是O(n)(分別計算f(1), f(2) ... f(n - 1)).
但是當n很大又或者還有其他處理的復雜度一疊加便會超時。

如果不學習矩陣乘法優(yōu)化的話,我們恐怕永遠不會想到計算遞推式還可以進行優(yōu)化。
實際上利用矩陣乘法,我們可以將O(n)的計算遞歸式的復雜度降至O(logn)


優(yōu)化遞歸式的特征

形如f(n) = a1 * f(n - 1) + a2 * f(n - 2) + ... + ak * f(n - k)+c (c為常數(shù))


本文討論的范疇

  • 形如 f(n) = f(n-1) + f(n-2) + .. + f(n-k) 的遞歸式(1)

  • 形如f(n) = a1 * f(n-1) + a2 * f(n-2) + .. + ak * f(n-k) 的遞歸式(2)

  • 形如f(n) = a1 * f(n-1) + a2 * f(n-2) + .. + ak * f(n-k) + c 的遞歸式(3)

實際上理解了最簡單的第一個遞歸式的原理,就很容易理解后面的兩種情況。每個前式都是后式的一種特殊情況。


理論基礎

首先給出斐波那契數(shù)列求第n項的O(logn)的做法,由它引出原理。

已知 :
f(n) = f(n -1) + f(n - 2); -- (1)
f(n - 1) = f(n - 1); -- (2)
由(1)(2)可以得到這樣的一個式子:
[ f(n) ] = [1, 1] * [f(n - 1)]
[f(n - 1)] [1, 0] * [f(n - 2)]

這就核及到矩陣乘法的運算規(guī)則。矩陣乘法的計算方式如下所示:

A = X * Y。必須滿足row(X) = colom(Y)。
A[i][j] = sum{x[i][k] * x[k][j]}。
row(A) = row(X), colom(A) = colom(Y)..

對于上式,f(n) = f(n - 1) + f(n - 2),f(n - 1) = f(n - 1) + 0,滿足斐波那契數(shù)列的規(guī)則。
我們設右邊靠左的式子為A,靠右的為F。

那么計算f(n),我們只需要計算A^(n - 1) * F。復雜度O(n)。
但是做冪運算,可以通過快速冪將復雜度從O(n)降到O(logn),因此總復雜度科技降到O(logn)。

通過這個例子我們能發(fā)現(xiàn)什么?很顯然的便是A與Y(左式與右二式,一下皆簡稱為A,X,Y)本質(zhì)上是一個東西,因此通過迭代,直接計算出第n項。

斐波那契數(shù)列是一個最簡單的例子,它也是(1)的典型例子。

廣義斐波那契數(shù)列

定義f(n) = a * f(n - 1) + b * f(n - 2).
與之前的區(qū)別僅僅在于前面的系數(shù)不是1,那么構造出等式只需要照葫蘆畫瓢即可。

[ f(n) ] = [a, b] [f(n - 1)]
[f(n - 1)] [1, 0] [f(n - 2)],本質(zhì)沒有變化。
那么對于f(n) = a1 * f(n - 1) + .... + ak * f(n - k),我們只需要構造一個k * k的矩陣。

(*)式便是一般情況的式子,其實只需要使得第一行滿足數(shù)列公式,其他行滿足f(i) = f(i)即可。
因此只需要令f[i][i - 1] = 1(下標從0開始),其他都是0即可使等式成立。

帶常數(shù)與系數(shù)的遞歸式

通過之前的經(jīng)驗我們不難看出,矩陣A,Y中的元素一定是每一次計算的時候必需的元素。這次多了一個常數(shù)c,因此c也要在A,Y中出現(xiàn)
對此,我們在需要在最后一行加上c,構造成一個(k + 1) * (k + 1)的矩陣,如下。

觀察一下(**)式,第1和k+1行的最后都為1,其他新增的空位全是0,如此便構造完成了。
至于原理,再通過矩陣乘法驗證一下不就好了嗎?

最后給出代碼實現(xiàn)(NOI2012 d1t3)
這道題就是一個裸的(3)式情況。

/* About: Matrix Fast Exponentiation to calculate Recursion with Coefficient and Constant From: NOI2012 d1t3 Description:Input: n, p, c, f(0), Mod, mod;Recursion: f(n) = (p * f(n-1) + c) % Mod;Output: f(n) % mod; Auther: kongse_qi Date:2017/05/19 */#include <cstdio> #include <cstring>#define read(x) scanf("%d", &x)typedef long long ll; long long mod;ll Mul (ll a, ll b) {ll ans = 0;for(; b; b >>= 1, a = (a + a) % mod) {if(b & 1) ans = (ans + a) % mod;}return ans; }struct Matrix{ll n, m, x[5][5];Matrix(){}Matrix(int a, int b):n(a), m(b){}Matrix operator * (const Matrix& a) {Matrix y(n, a.m);memset(y.x, 0, sizeof y.x);for (int i = 0; i < n; i++){for (int k = 0; k < m; k++){if (!x[i][k]) continue;for (int j = 0; j < a.m; j++){y.x[i][j] = (Mul(x[i][k], a.x[k][j]) + y.x[i][j]) % mod;}}}return y;}Matrix Poww(ll times){Matrix y = *this, z = y;for(--times; times > 0; times >>= 1, z = z * z){if(times & 1) y = y * z;}return y;} };void Create(Matrix& x, Matrix& f, ll a1, ll p, ll c) {f.n = x.n = x.m = 3;f.m = 1;memset(x.x, 0, sizeof x.x);x.x[0][0] = p;x.x[0][2] = x.x[1][0] = x.x[2][2] = 1;f.x[0][0] = (Mul(a1, p) + c) % mod; f.x[1][0] = a1;f.x[2][0] = c;return ; }int main() {Matrix x, f;ll a1, n, Mod, c, p;scanf("%lld%lld%lld%lld%lld%lld", &mod, &p, &c, &a1, &n, &Mod);Create(x, f, a1, p, c);Matrix y = x.Poww(n - 1) * f; printf("%lld\n", y.x[0][0] % Mod);return 0; }

至于一些更簡單的情況,以下有幾道練習。
luogu P1962 斐波那契數(shù)列
luogu P1349 廣義斐波那契數(shù)列
Vijos 1067 Warcraft III 守望者的煩惱
NOI2012 隨機數(shù)生成器

最后一題值得注意的是,最后幾個點乘法過程會炸出longlong,因此需要使用類快速冪的方法快速求和(積),邊加邊取模。

至此結束。
箜瑟_qi
** 7:58 2017.05.25**

轉(zhuǎn)載于:https://www.cnblogs.com/kongse-qi/p/6901951.html

總結

以上是生活随笔為你收集整理的矩阵乘法优化递归式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。