题目大意:给定 \(n\) 个数,每次能够任意选两个数 \(a_i,a_j\) 相加,把相加的结果做为一个新数继续执行此操做,直到只剩一个数为止。现要求使最后得出的这个数最小。ios
一个显然的贪心策略:每次选最小的两个数相加,获得一个新数,而后继续。可是,若是按照这样的思路,那么每次获得新数后这个序列的单调性就有可能会被破坏。数组
如何解决呢?很显然的一种方法,将新数加入序列后,再把这个序列排序。然而这样作彷佛会超时。C++ STL 中提供了一种巧妙地解决方法:\(\mathtt{priority\_queue}\)。它地本质是建一个二叉堆,而后每当插入一个数,就维护这个二叉堆。那么显然,在这个题中,咱们须要建一个小根堆,使较小的元素老是先被取出进行操做。less
而后须要解决一个问题:spa
如何创建小根堆(使用\(\mathtt{priority\_queue}\))?code
这样:priority_queue<int,vector<int>,greater<int> >q;
。其中第一个 int
表明小根堆中存储的数据类型, vector<int>
表明存储的方式(vector
就是数组), greater<int>
就是从小到大(即小根堆)。而后大根堆的话就是 priority_queue<int,vector<int>,less<int> >q;
。排序
因而,作法就呼之欲出了:没读入一个数字,就插入小根堆中。而后,当元素个数大于等于 2 时循环,每次取出队首的两个元素相加,答案加上这个数字,再令新数入队便可。队列
请注意:这里为何循环条件时元素个数大于等于 2而不是 队列不为空 呢?用兔队的一句话来回答:it
参考代码:io
#include <iostream> #include <stdio.h> #include <queue> using namespace std; int n,w; priority_queue<int,vector<int>,greater<int> >q; int main() { long long ans=0; scanf("%d",&n); for(int i=1;i<=n;i++){scanf("%d",&w);q.push(w);} while(q.size()>=2) { int x=q.top();q.pop(); int y=q.top();q.pop(); x+=y; ans+=x; q.push(x); } printf("%lld\n",ans); return 0; }