题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2339
解题报告:题目太长了,比赛的时候根本看不懂,完了之后问了什么意思,发现好简单,就是输入n个数据,把这n个数据放入一个集合中,然后每次从集合中取出两个最小的数,求出他们的和,并且把这个和加入到结果当中 ,并且要把这个和放入到集合当中,然后再次从集合中取出两个数,就这样一直做,直到这个集合为空。其实就是用一个最小堆,然后每次从堆里面去粗两个数,求和再把这个和插入到堆中,也就是最裸的堆,要注意的是这题数据范围超出int了,要用long long 。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 typedef long long INT; 7 8 INT tree[500005]; 9 int rear; 10 11 void push(INT d) 12 { 13 tree[++rear] = d; 14 int p = rear; 15 while(p/2 >= 1 && tree[p] <= tree[p/2]) 16 { 17 swap(tree[p],tree[p/2]); 18 p /= 2; 19 } 20 } 21 22 INT get_top() 23 { 24 INT d = tree[1]; 25 swap(tree[1],tree[rear--]); 26 return d; 27 } 28 29 void pop(int p) 30 { 31 int i = p , j = 2*p; 32 if(j > rear) 33 return ; 34 if(j + 1 <= rear && tree[j + 1] < tree[j]) 35 j++; 36 if(tree[i] >= tree[j]) 37 { 38 swap(tree[i],tree[j]); 39 pop(j); 40 } 41 else return; 42 } 43 44 int main() 45 { 46 int T,n; 47 scanf("%d",&T); 48 while(T--) 49 { 50 scanf("%d",&n); 51 INT sum = 0,d = 0,x = 0; 52 rear = 0; 53 for(int i = 0;i < n;++i) 54 { 55 scanf("%lld",&d); 56 push(d); 57 } 58 for(int i = 1;i<n;++i) 59 { 60 x = get_top(); 61 pop(1); 62 x += get_top(); 63 pop(1); 64 sum += x; 65 push(x); 66 } 67 printf("%lld\n",sum); 68 if(T) printf("\n"); 69 } 70 return 0; 71 }