洛谷【P1090】合并果子&&洛谷【P1334】瑞瑞的木板
浅谈堆:https://www.cnblogs.com/AKMer/p/10284629.html
合并果子题目传送门:https://www.luogu.org/problemnew/show/P1090
瑞瑞的木板题目传送门:https://www.luogu.org/problemnew/show/P1334
瑞瑞的木板把题目转化成每次合并两块木板变成块就跟合并果子一样了。
显然,对于权值越大的数字我希望它的合并次数越少越好,所以我们每次选当前有的数字里两个最小的拿出来合并,这个可以用小根堆解决。
时间复杂度:\(O(nlogn)\)
空间复杂度:\(O(n)\)
代码如下:
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn=2e4+5;
int n;
ll ans;
int read() {
int x=0,f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
return x*f;
}
struct Heap {
int tot;
int tree[maxn];
void ins(int v) {
tree[++tot]=v;
int pos=tot;
while(pos>1) {
if(tree[pos]<tree[pos>>1])
swap(tree[pos],tree[pos>>1]),pos>>=1;
else break;
}
}
int pop() {
int res=tree[1];
tree[1]=tree[tot--];
int pos=1,son=2;
while(son<=tot) {
if(son<tot&&tree[son|1]<tree[son])son|=1;
if(tree[son]<tree[pos])
swap(tree[son],tree[pos]),pos=son,son=pos<<1;
else break;
}
return res;
}
}T;
int main() {
n=read();
for(int i=1;i<=n;i++) {
int x=read();
T.ins(x);
}
for(int i=1;i<n;i++) {
int x=T.pop()+T.pop();
ans+=x;T.ins(x);
}
printf("%lld\n",ans);
return 0;
}