题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=5884
优先取最小的,因为最先取得加的次数最多
并且 每次最好就合并k个,那么这种情况时,n=1+(k-1)*m, m∈N
所以(n-1)%(m-1)不为0时,要先取掉 前(n-1)%(m-1)+1个,这样可以让后面比较大的数字合并次数减少
一开始用set做哈夫曼树 但会超时
所以用两个双端队列,一个保存原来的值,一个保存合并后的值
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int maxn=100000+5;
typedef long long LL;
LL a[maxn],N,T;
deque<LL> Q1,Q2;
LL get()
{
LL temp;
if(Q1.empty()){
temp=Q2.front();
Q2.pop_front();
}
else if(Q2.empty()){
temp=Q1.front();
Q1.pop_front();
}
else{
if(Q1.front()>Q2.front()){
temp=Q2.front();
Q2.pop_front();
}
else {
temp=Q1.front();
Q1.pop_front();
}
}
return temp;
}
bool bEmpty(){
return Q1.empty()&&Q2.empty();
}
bool check(int k)
{
if(k==1) return false;
Q1.clear(); Q2.clear();
for(int i=0;i<N;i++) Q1.push_back(a[i]);
LL sum=0,temp=0;
if((N-1)%(k-1)){
for(int i=0;i<(N-1)%(k-1)+1&&!bEmpty();i++)
temp+=get();
sum+=temp;
if(!bEmpty()) Q2.push_back(temp);
}
while(!bEmpty())
{
temp=0;
for(int i=0;i<k&&!bEmpty();i++)
temp+=get();
sum+=temp;
if(sum>T) return false;
if(!bEmpty()) Q2.push_back(temp);
}
return true;
}
int BinarySearch()
{
if(N==0) return 0;
int L=1,R=N,mid;
while(L<R){
mid=(R+L)/2;
if(check(mid)) R=mid;
else L=mid+1;
}
return L;
}
int main()
{
int t; scanf("%d",&t);
while(t--)
{
scanf("%lld%lld",&N,&T);
for(int i=0;i<N;i++)
scanf("%lld",&a[i]);
sort(a,a+N);
cout<<BinarySearch()<<endl;
}
return 0;
}