合并果子2之蚂蚁搬沙

合并果子2之蚂蚁搬沙


Description


山谷中住着一个巨大的蚂蚁王国,蚁穴外有一个整洁的广场,天气晴好时蚁群常在那里举行各种活动。这天夜里,天降果子尘,第2天,广场上堆满了大大小小的果子堆,蚁哨出去数了数共有n堆,蚁后要求她的臣民将广场上的果子堆清理掉。具体办法是:每次可以把广场上的任意k堆果子合并成一堆,重复进行直至所有的果子堆最终合并成一堆。规定(1):2≤k≤m,m由蚁后指定,(2):每次合并k堆果子的代价是这k堆果子子的重量和。 
你的任务是,对给定的n和m,计算出将n堆果子最终合并成1堆的最小总代价。 
例如,广场上有7堆果子,其重量分别为45,13,12,16,9,5,22。当m=3时,这些果子堆合并成一堆的最小总代价为199。当m=5时,这些果子堆合并成一堆的最小总代价为148。
Input
包含n+2个整数(n≤100000),其中第一行2个正整数,分别表示n堆果子和每次合并时可以合并的最大堆数m,从第二行开始有n个数,表示n堆果子的重量(1~500),数与数之间用空格隔开。
Output
只包含一个正整数,表示将n堆果子合并成1堆所需的最小总代价。


Sample Input


7 3
45 13 12 16 9 5 22
Sample Output

199 

 

思路

1.这一题是 [Noip2004]合并果子(https://blog.csdn.net/qq_39925003/article/details/86763660) 的普通形式。
2.因为每次可以合并2-m堆果子,所以需要每次合并尽量多堆数果子,即每次都合并m堆。
3.本题,实质上是构造一棵完全m叉树,但已有的n堆果子可能无法组成一棵完整的,所以我们往堆里加若干堆权值为0的果子堆,设其数量为x,以补充成一棵完全m叉树。
关于x的计算方式:因为每次可以合并m堆,所以可以合并成(n/m)堆完整的,并且还剩下(n%m)堆,n堆就等同于(n/m)+(n%m)堆,一直进行此运算,直到(n<=m)时,n距离完整的m堆还差(m-n)堆,即(m-n)就是添0的个数。

代码

#include<bits/stdc++.h>
using namespace std;
int n,m,k,t,pass,nn,mod,c;
long long ans=0;
priority_queue<int,vector<int>,greater<int> >d;
int main()
{
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&k);
		d.push(k);
	}
	nn=n;
	while(true)
	{
		c=nn/m;
		mod=nn%m;
		nn=c+mod;
		if(nn<=m)
		{
			pass=m-nn;
			break;
		}
	}
	for(int i=1;i<=pass;i++)//添加pass个0 
		d.push(0);
	while(true)
	{
		t=0;
		for(int i=1;i<=m;i++)//选择m个小值 
		{
			t=t+d.top();
			d.pop();
		}
		ans=ans+t;
		if(d.empty())
		{
			printf("%lld",ans);
			return 0;
		}
		d.push(t);
	}
	return 0;
} 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值