• 题意
    • 有n个编号1~n权值ai~an的球以及n个1~n的盒子,开始n个球都放在第一个盒子里
    • 每次进行一次操作,即将某个盒子里的所有球取出,然后分成不为空的两堆或者三堆,放入空盒中,花费为取出的所有球取值总和
  • 题解
    • 转化一下,就是将总和为 sum 的数字拆分为给定数列,每次只能拆分为两堆或者三堆,其花费为当前堆的大小,求最小花费。
    • 反过来,其实就是一个给定序列,合成一堆,求最小花费
    • 那么就是石子合并问题了,求一个哈夫曼树上所有非叶子节点的总和即可
  • 代码
    • #include<queue>
      #include<cstdio>
      #include<cstdlib>
      #include<iostream>
      #include<algorithm>
      using namespace std;
      #define ll long long
      const int maxn=200010;
      priority_queue<ll,vector<ll>,greater<ll> >q;
      ll a[maxn];
      int main() {
      	int N;
      	ll ans=0,tmp;
      	scanf("%d",&N);
      	for(int i=1; i<=N; i++) {
      		scanf("%I64d",&a[i]);
      		q.push(a[i]);
      	}
      	if(N==1) {
      		printf("0\n");
      		return 0;
      	}
      	if(N%2==0) q.push(0);
      	while(q.size()>3) {
      		tmp=q.top();
      		q.pop();
      		tmp+=q.top();
      		q.pop();
      		tmp+=q.top();
      		q.pop();
      		ans+=tmp;
      		q.push(tmp);
      	}
      	while(!q.empty()) {
      		ans+=q.top();
      		q.pop();
      	}
      	cout<<ans<<endl;
      	return 0;
      }
      

发表评论

邮箱地址不会被公开。 必填项已用*标注