To_Heart—题解——归并排序


果果最近新学习了归并排序,对于归并排序时有两个序列ai和aj,果果将他们合并所需要的花费为ai+aj ,即两个序列⻓度之和。果果现在能⼀次最多合并k个序列,其花费为k个序列的⻓度之 和。但是教练为了不让果果浪费资源,让他进⾏完归并排序后的花费不超过C。果果为了偷懒想每次合 并的序列数尽可能少,于是果果想请你告诉他,他能完成归并排序且总的花费⼩于C最⼩的k是多少 呢。

输入格式

第⼀⾏有两个整数 n ,C表示有n个序列,总的花费不超过C。 第⼆⾏有n个整数ai,表示要合并的n个序列,每个序列的⻓度。

输出格式

输出为⼀⾏,表示最⼩的k。

样例

样例输入

5 20
1 2 3 4 5

样例输出

4

样例解释

先合并(1,2)为3 ,再合并(3,3,4,5) 为 15。总花费为18⼩于20。

题解

题解

首先,如果合并次数越多,则花费就越多;反之,如果合并次数越少,则花费就越少,满足二分的条件,而合并次数由每次合并的个数决定,所以只需要二分每次合并的个数即可。

但是,设每次合并k个,我们不可以保证最后一次k个合并后只剩下一个数,所以不可以保证最优。

对于每次合并,我们都会留下一个数,所以每次可以丢掉k-1个数,最后我们希望丢掉n-1个数,所以一开始我们就需要合并(n-1)%(k-1)+1个数,这样就可以保证最后一次操作后只剩下一个数,又因为我们需要让值最小,所以一开始合并的数值要小,所以先排序。

代码

#include<bits/stdc++.h>
using namespace std;

int a[100005];
int n,m;

bool Cheak(int x){
    
    
	priority_queue<int,vector<int>,greater<int> >q;
	int tot=0;
	int ans=0;
	int now=(n-1)%(x-1);
	if(now>0){
    
    
		for(int i=1;i<=now+1;i++){
    
    
			tot+=a[i];
		}
		ans+=tot;
		q.push(tot);
		tot=0;
	}
	for(int i=now+2;i<=n;i++){
    
    
		q.push(a[i]);
	}
	while(!q.empty()){
    
    
		tot=0;
		for(int i=1;i<=x;i++){
    
    
			if(!q.empty()){
    
    
				tot+=q.top();
				q.pop();
			}
			else
				break;
		}
		ans+=tot;
		if(!q.empty()){
    
    
			q.push(tot);
		}
	}
	if(ans>m)
		return 0;
	return 1;
}

int main(){
    
    
	scanf("%d%d",&n,&m);
	//cerr<<n<<' '<<m<<endl;
	for(int i=1;i<=n;i++){
    
    
		scanf("%d",&a[i]);
		//cerr<<a[i]<<' ';
	}
	sort(a+1,a+n+1);
	int l=2,r=n;
	int ans=0;
	while(l<=r){
    
    
		int mid=(l+r)>>1;
		if(Cheak(mid)){
    
    
			r=mid-1;
			ans=mid;
		}
		else{
    
    
			l=mid+1;
		}
	}
	printf("%d",ans);
	return 0;
} 
/*
10 75
6 6 10 4 2 7 9 9 6 10
*/

Supongo que te gusta

Origin blog.csdn.net/xf2056188203/article/details/109432285
Recomendado
Clasificación