description
在乙個操場上擺放著一排n堆石子。現要將石子有次序地合併成一堆。規定每次只能選相鄰的2堆石子合併成新的一堆,並將新的一堆石子數記為該次合併的得分。
試設計乙個演算法,計算出將n堆石子合併成一堆的最小得分。
input
第一行是乙個數n。
以下n行每行乙個數a,表示石子數目。
output
共乙個數,即n堆石子合併成一堆的最小得分。
sample input41
111sample output
8hint
對於 100% 的資料,1≤n≤40000
對於 100% 的資料,1≤a≤200
題解:一般的石子合併在dp+四邊形優化後複雜度為o(n
2n^2
n2),這題資料範圍顯然不行。
所以此題正解為garsiawachs演算法
下面簡述一下該演算法的流程以及結論:
(為了方便起見,我們規定a[0] = a[n+1] = inf)
①從序列的左端開始找第乙個滿足a[k−1]≤a[k+1]的 k,然後合併a[k−1]和a[k]
②從當前合併位置向左尋找第乙個滿足a[j]>a[k-1] + a[k]的j,然後將合併後的值插在a[j]後
③重複上述過程(n-1次),直到只剩下一堆,總合併代價即為①中每次合併代價之和
演算法複雜度為o(nlogn)
該定理保證,如此操作後答案不會改變
acode:
//o(nlogn)
#include
#include
typedef
long
long ll;
using
namespace std;
const
int mx =
4e4+7;
const
int inf =
0x3f3f3f3f
;int n,m,ans,a[mx]
;int
main
(int argc,
char
const
*ar**)
}//將a[k-1] 和 a[k] 合併
a[k-1]
+= a[k]
;for
(int j = k;j < m;
++j)
a[j]
= a[j +1]
; ans +
= a[
--k]
;//從k向左找第乙個a[j] > a[k - 1] + a[k] 的 j,把合併後的值插在a[j]後面
while
(k >
0&& a[k-1]
<= a[k]
) a[m]
= inf;
m--;}
cout << ans << endl;
return0;
}
regina8023
lwq12138
石子合併 BZOJ 3229
題目傳送門 題意 石子合併問題一般來說都是o n 3 的複雜度,如果用四邊形不等式優化的話可以使時間複雜度降低到o n 2 的複雜度,但是這個題目的資料範圍是40000,所以這個題要用到garsiawachs演算法,可以使時間複雜度降到o n logn 從而解決這個題目。include includ...
BZOJ 3229 Sdoi2008 石子合併
時間限制 3 sec 記憶體限制 128 mb 提交 497 解決 240 提交 在乙個操場上擺放著一排n堆石子。現要將石子有次序地合併成一堆。規定每次只能選相鄰的2堆石子合併成新的一堆,並將新的一堆石子數記為該次合併的得分。試設計乙個演算法,計算出將n堆石子合併成一堆的最小得分。第一行是乙個數n。...
282 石子合併
設有n堆石子排成一排,其編號為1,2,3,n。每堆石子有一定的質量,可以用乙個整數來描述,現在要將這n堆石子合併成為一堆。每次只能合併相鄰的兩堆,合併的代價為這兩堆石子的質量之和,合併後與這兩堆石子相鄰的石子將和新堆相鄰,合併時由於選擇的順序不同,合併的總代價也不相同。例如有4堆石子分別為 1 3 ...