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\) ,就是最小化直線的截距
我們可以將 \((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
在樹上查詢最大/小值,求完後再更新線段樹即可