1. 程式人生 > 其它 >「JOISC 2019 Day4」蛋糕拼接 3

「JOISC 2019 Day4」蛋糕拼接 3

loj 3039
NKOJ

Description

\(n\)個蛋糕,每個蛋糕有\(w_i,h_i\)。選\(m\)個蛋糕滿足\(\sum\limits_{j=1}^mw_{k_j}-\sum\limits_{j=1}^m|h_{k_j}-h_{k_{j+1}}\ |\)
因為蛋糕擺成一個環所以\(k_1=k_{m+1}\)

Solution

我因為最近天天做dp,直接就往dp上想的,其實是思維僵化。
然後本來可以騙46分的,因為沒有考慮到答案可能是負數+資料點捆綁直接寶菱。
dp就字首和優化dp就可以做了,很好寫。
當然前面肯定要想到\(\sum\limits_{j=1}^m|h_{k_j}-h_{k_{j+1}}\ |\)

這個的最小值,顯然是按\(h\)從小到大排後得到的,因此其實是\(2*(maxh-minh)\)
這樣按\(h\)排序,消除影響。
列舉最後一個選的點\(i\),發現第一個選的點\(j\)是具有決策單調性的(只會打表)
整體二分+可刪對頂堆

這東西挺噁心的,總之我調了好久,經常推翻重來

總結一下:

整體二分:維護兩個指標\(tl\),\(tr\),複雜度是\(nlog_2^2n\)的因為\(log_2n\)層,每次\([L,R]\)結束時,\(tl=L,tr=R\)。左遞迴開始時肯定是取\([L,R]\)中一個點\(pos\),\(tl=pos,tr=pos\),左邊遞迴結束時一定是也\(tl=pos,tr=pos\)

(左dfs樹最靠右的葉子),此時再右遞迴轉移到 \(tl=R,tr=R\)。考慮這一層的轉移,顯然是\(R-L+1\)次,每次\(O(log_2n)\),而又有有\(log_2n\)層。
當然上面的複雜度證明中,不一定是確切的等於(如 \(tl\) 會有和 \(mid-m+1\)\(min\),每層跟\(mid\)有關總體也是\(nlog_2n\)級別的),易證影響不大/kk。

對頂堆:因為你需要維護前\(m\)大的和(\(sumw\)),如果你只存一個大根堆,刪除或者加入是維護不了的。
因此前\(m\)大的數存入小根堆\(Q1\)裡,其它小的數存入大根堆\(Q2\),每次加入一個數判斷如果大於\(Q1\)

,\(Q2\)分界,把\(Q1.top()\)加入\(Q2\),把該數加入\(Q1\)。否則直接加入\(Q2\)
然後刪除也維護兩個可刪堆\(D1,D2\)。每次刪除的時候判斷刪的數是在\(Q1\)中則加入\(Q2\),反之……
每次取出堆頂前判斷是如果已經在可刪堆內,直接刪了(這是可刪堆的常規操作……)

!!! 這裡我犯過一個錯誤

你維護的\(sumw\)不是你\(Q1\)裡面實際所有值的和。而是裡面沒有在\(D1\)中(沒被刪)的和。
\(Q1-D1\)才是真正的前\(m\)大。\(Q1\)裡面還存在著一些已經死去的傀儡……
所以實際上\(Q1.size()\)不一定等於\(m\),我們需要單獨維護一個\(sz1\)(這個很簡單)

實現細節:不知道我的實現方式會不會比別人複雜

強制\(Q1\),\(Q2\)的堆頂是存在的(沒被刪),需要每次\(pop()\)後,刪點即可。
Add的就是上面對頂堆說的那堆。
Del比較複雜,如果刪除的是在\(Q1\)中的,用\(Q2.top()\)替代刪除的那個,即把\(Q2.top()\)加入\(Q1\),刪除的值加入\(D1\)。這樣也保證了\(sz1\)守恆。

以後寫部落格儘量巨集觀一點,不要太囉嗦,不過我感覺題目都好細節呀。