描述 Description
FarmerJohn想修理牧场栅栏的某些小段。为此,他需要N(1<=N<=20,000)块特定长度的木板,第i块木板的长度为Li(1<=Li<=50,000)。然后,FJ去买了一块很长的木板,它的长度正好等于所有需要的木板的长度和。接下来的工作,当然是把它锯成需要的长度。FJ忽略所有切割时的损失——你也应当忽略它。
FJ郁闷地发现,他并没有锯子来把这块长木板锯开。于是他把这块长木板带到了Farmer Don的农场,想向FD借用锯子。
作为一个有商业头脑的资本家,FarmerDon没有把锯子借给FJ,而是决定帮FJ锯好所有木板,当然FJ得为此付出一笔钱。锯开一块木板的费用,正比于木板的长度。如果这块木板的长度是21,那么锯开它的花费便是21美分。
谈妥条件后,FD让FJ决定切割木板的顺序,以及每次切割的位置。请你帮FJ写一个程序,计算为了锯出他想要的木板,他最少要花多少钱。很显然,按不同的切割顺序来切开木板,FJ的总花费可能不同,因为不同的切割顺序,会产生不同的中间结果。
输入格式 Input Format
* 第1行: 一个正整数N,表示FJ需要木板的总数
* 第2…N+1行: 每行包含一个整数,为FJ需要的某块木板的长度
输出格式 Output Format
* 第1行: 输出一个整数,即FJ完成对木板的N-1次切割的最小花费
emm 这道题和合并果子一模一样。
#include
using namespace std;
const int maxn = 2e4 + 100;
typedef long long LL;
LL x, sum, n;
template <typename T>
inline void read(T &s) {
s = 0;
T w = 1, ch = getchar();
while (!isdigit(ch)) { if (ch == '-') w = -1; ch = getchar(); }
while (isdigit(ch)) { s = (s << 1) + (s << 3) + (ch ^ 48); ch = getchar(); }
s *= w;
}
namespace MakeHeap {
LL size;
LL heap[maxn];
inline void swap(LL &aa, LL &bb) { aa ^= bb ^= aa ^= bb; }
inline void up(LL p) {
while (p > 1) {
if (heap[p] < heap[p / 2]) {
swap(heap[p], heap[p / 2]);
p /= 2;
}
else break;
}
}
inline void insert(LL val) {
heap[++size] = val;
up(size);
}
inline LL GetTop() { return heap[1]; }
inline void down(LL p) {
LL s = p * 2;
while (s <= size) {
if (s < size && heap[s] > heap[s + 1]) s++;
if (heap[s] < heap[p]) {
swap(heap[s], heap[p]);
p = s, s = p * 2;
}
else break;
}
}
inline void Extract() {
heap[1] = heap[size--];
down(1);
}
}
using namespace MakeHeap;
int main() {
read(n);
for (int i = 1; i <= n; ++i) {
read(x); insert(x);
}
sum = 0;
while (size > 1) {
LL x1 = GetTop();
Extract();
LL x2 = GetTop();
Extract();
sum += (x1 + x2);
insert(x1 + x2);
}
printf("%lld\n", sum);
return 0;
}