題目連結:
資料加強版連結:
題目描述
有一個長度為 ∑ai 的木板,需要切割成 n 段,每段木板的長度分別為 a1,a2,…,an。
每次切割,會產生大小為被切割木板長度的開銷。
請你求出將此木板切割成如上 nn 段的最小開銷。
輸入格式
第 1 行一個正整數表示 n。
第 2 行包含 nn 個正整數,即 a1,a2,…,an。
輸出格式
輸出一個正整數,表示最小開銷。
資料範圍
對於全部測試資料,滿足 1≤n,ai≤10^5。
樣例輸入:
5
5 3 4 4 4
樣例輸出:
47
nlogn解法
核心思想:貪心
正向考慮題意的話,需要每次將長木板較平均的分割成兩塊,再每次分割出裡面最小的,怎麼才最平均呢?還得找最大值?個人覺得不是那麼好處理,可以考慮下逆向思維,轉換一下題意。
如何轉換題意呢?將一塊長木板分割為n段,每次的花費為被分割的木板長度,可以等價於被分割成的兩塊合成一塊時,花費為合成的兩塊的長度和,便轉化成了怎樣使它合併成一塊的花費最小問題。(舉個例子,就比如一個長為4的分成一個1一個3,花費為4,跟一個1和一個3合併成一個4,花費為1+3時等價的)
思路:
考慮每次取出兩個最小的合成一個更大的,直到最後只剩一個。
證明:
怎麼證明這個貪心是對的呢?我們可以假設有三個木塊a1<a2<a3,如果取a1,a2合併,需要的花費為(a1+a2)+(a1+a2+a3),如果不取兩個最小的,而取a2,a3,需要花費為(a2+a3)+(a2+a3+a1)顯然比第一種要大。那麼如何推廣到一般情況呢?我們可以這樣想,合併了兩個之後,費用肯定要加上兩個的和,兩個合併成的一個肯定還需要與其他的合併,而用遞迴去想這一部分的花費可以看成是大小固定的,就是說你合併成的還需要去和其他的合併求和,而最終下次合併的和是相同的,那麼讓兩個合併的花費盡量小,花費不就小了嗎?
程式碼實現
怎樣每次找到兩個最小的呢,並加入合併成的那個?我們考慮使用STL自帶的最小堆-優先佇列priority_queue。
複雜度分析:
優先佇列的插入查詢均為logn,複雜度為O(n)*O(logn)即O(nlogn)。
程式碼:
O(n)解法
考慮優化掉每次插入查詢的logn。每次合併成的新的木板肯定是載增大的,也就是說合成的木板是有序的,那麼我們使沒有被合併的那些木板變得有序,每次考慮取兩者隊首元素中較小的,用兩個佇列維護,因為有序所以隊首元素為最小值。對初始佇列的排序考慮桶排。可以在On的時間內完成此題了。(洛谷貌似卡讀入了,所以加了個快讀)
詳見程式碼: