1. 程式人生 > 其它 >Flink 任務排程機制幾個重要概念

Flink 任務排程機制幾個重要概念

一些關於DP的小優化:

字首和優化(用於 \(dp[i]=dp[i-k]+v[i]\)的轉移)

bitset優化(01揹包(價值能否取到),常數為 \(\omega=1/32\)

單調佇列優化(求恆長區間最大/小值)

二進位制優化(完全揹包問題,\(O(n^2\ logn)\) ):P1776

線段樹優化:CF1557D

斜率優化:見下文

樹鏈剖分(DDP


斜率優化:

本蒟蒻終於被迫學習斜率優化了

這類問題的優化的轉移方程是:\(b(i)=max/min\{y(j)-k(i)\times x(j)\},j < i\)

本題為例:

一個樸素的轉移方程:

\[dp[i]=min(dp[j]+(i-j-1+sum[i]-sum[j]-L)^2) \]

其中,\(sum[i] = \sum_{k=1}^jc[k]\)

再合併,令 \(pre[i]=sum[i]+i\)

得:

\[dp[i]=min(dp[j]+(pre[i]-pre[j]-(L+1))^2) \]

強拆!

\[dp[i]=min(dp[j]+(pre[i]-(L+1))^2-2(pre[i]-(L+1))\times pre[j]+pre[j]^2) \]

移項:

\[dp[i]-(pre[i]-(L+1))^2=min(dp[j]-2(pre[i]-(L+1))\times pre[j]+pre[j]^2) \]

\[\begin{aligned} b_i&=dp[i]-(pre[i]-(L+1))^2,\\ x_j&=pre[j],\\ y_j&=dp[j]+pre[j]^2,\\ k_i&=2(pre[i]-(L+1))\\ \end{aligned}\]

那就變成了 \(y = kx+b\)

的轉換式 \(b = y - kb\)

我們要最小化 \(b\) ,就是最小化直線的截距

我們可以將 \((x_j,y_j)\) 看作平面上的點,現在有一條斜率為 \(k_i\) 的直線,從下往上移動,碰到的第一個點就是我們的轉移決策點(因為要最小化 \(b_i\)

實際上,我們只需要維護下凸殼的那些點,而對於本題,顯然 \(k_i\)\(i\) 的增大而增大,所以我們只需要用一個單調佇列來維護凸殼上的點

借用 OI-Wiki 中的圖:

我們令 \(K(q_{e-1},q_e)\)\((x_{q_{e-1}},y_{q_{e-1}})\)\((x_{q_{e}},y_{q_{e}})\)

兩點連線的斜率

顯然,我們要找的決策點就是凸殼中滿足 \(K(q_{e-1},q_e)\le k_i < K(q_e,q_{e+1})\) 的點 \(e\)

因為 \(k_i\) 是遞增的,所以下一次 DP 只需要從 \(e\) 開始找決策點,這樣均攤下來就是 \(O(1)\)

又因為 \(x_i=pre[i]\) 是遞增的,所以點 \(i\) 一定會加入到凸殼中,我們只需要將 \(K(q_{e-1},q_e)<=K(q_e,(x_i,y_i))\) 的點彈出,再將 \(i\) 加入到佇列即可

注意:佇列的初始狀態應該是有一個點 (0,0) ,否則 \(c_1\) 將永遠無法和後面的玩具合併,導致錯誤!


一般化

但如果我們將上述題目的條件改改,使得 \(c_i\) 可以為負,那麼這時候 \(k_i\)\(x_i\) 就不單調遞增了,是不是就做不了了???

當然不是啊,不然我提出這個問題幹嘛

對於 \(k_i\) (斜率)不單調的話,我們直接在凸殼上二分,還是找滿足原來那個條件的點即可

但如果 \(x_i\) 不是單調的,我們就很難去更新凸殼了

一種方法就是用平衡樹維護凸包,就是找到 \(x_j \le x_i \le x_{j+1}\) 的地方,根據凸包的性質不斷向兩邊刪點(或者自己本來就在凸包裡面就不用管了)

但用平衡樹十分滴複雜,有沒有更好寫的演算法?(其實用 set 是可以實現的)

有!就是我們萬能的 CDQ分治

我們假定分治到 \((l,r)\),且 \((l,mid)\) 已經處理完了,現在要對 \((mid+1,r)\) 進行貢獻

注意:這時候 \((mid+1,r)\)沒有分治下去!

我們先將 \((l,mid)\) 的點以 \(x\) 為第一關鍵字, \(y\) 為第二關鍵字排序,然後就直接求一遍凸殼

然後我們再將 \((mid+1,r)\) 按照斜率 \(k\)編號從小到大排序

這時候我們就可以正常像上面用單調佇列跑 DP

轉移完後,顯然 \((l,mid)\) 的決策點已經沒有用處了,我們可以直接將其捨棄掉,轉到 \((mid+1,r)\) 的分治

整個分治的時間複雜度是 \(O(nlog^2n)\) 的。

當然,我們也可以用 李超線段樹 直接跑 DP ,就是將上面的 \(k,x,y,b\) 稍微換一下,每次 DP 在樹上查詢最大/小值,求完後再更新線段樹即可