其实这是哈夫曼树,一开始用优先队列写超时,后来发现不用优先队列,因为每次相加后的值总是大于之前相加的,那么只需要用普通队列就可以了,而且这个队列是单调递增的,然后取原数组的头或者单调队列的头就可以了。
但是没有考虑到(n-1)%(k-1)==0,感觉这个条件比较难想,需要实现预处理合并一次。
感觉可以用数学归纳法得出。
//
// main.cpp
// Richard
//
// Created by 邵金杰 on 16/9/22.
// Copyright © 2016年 邵金杰. All rights reserved.
//
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;
const int maxn=200000+100;
int val[maxn];
int n;
ll T;
bool merge(int k)
{
ll ans=0;
int head=1,tail=n;
queue<ll> q;
if(k!=1&&(n-1)%(k-1)!=0){
for(int i=1;i<=(n-1)%(k-1)+1;i++)
ans+=val[i];
head=(n-1)%(k-1)+2;
q.push(ans);
}
while(head<=tail||!q.empty())
{
int sum=0;
for(int i=0;i<k;i++)
{
if(head<=tail&&!q.empty()&&val[head]<q.front()) {sum+=val[head++];}
else if(!q.empty()&&head<=tail&&q.front()<=val[head]) {sum+=q.front();q.pop();}
else if(q.empty()) {sum+=val[head++];}
else if(head>tail) {sum+=q.front();q.pop();}
}
ans+=sum;
if(ans>T) break;
q.push(sum);
if(q.size()==1&&head>tail) break;
}
return ans>T?false:true;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%lld",&n,&T);
for(int i=1;i<=n;i++) scanf("%d",&val[i]);
sort(val+1,val+1+n);
int k=0;
int l=1,r=n;
while(l<r)
{
k=(l+r)/2;
if(merge(k)) r=k;
else l=k+1;
}
printf("%d\n",l);
}
return 0;
}