http://acm.hdu.edu.cn/showproblem.php?pid=5884
二分加多叉哈夫曼树
优雅的优先队列可以卡过,但必定不会有双队列O(n)写更优雅,学到了
需要注意的坑点是,k叉哈夫曼树,每次减少k-1个元素,当(n-1)%k!=0时,也就是每次减掉k-1个,最后剩的数多于一个时
如果最后在拿掉这些并不是最优的,最后必然剩很多大数,更优的策略应该是先拿掉这些多余的,然后在k个k个的合并
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
long long a[maxn];
long long t;
int n;
int check(int k)
{
int i;
long long cost=0;
queue<long long>q1,q2;
for(i=0;i<n;i++)
q1.push(a[i]);
int num=(n-1)%(k-1)+1;
long long now=0;
while(num--)
{
long long temp=q1.front();
q1.pop();
now+=temp;
}
cost+=now;
q2.push(now);
int nn=(n-1)/(k-1);
while(nn--)
{
num=k;
now=0;
while(num--)
{
if(q1.empty())
{
now+=q2.front();
q2.pop();
}
else if(q2.empty())
{
now+=q1.front();
q1.pop();
}
else if(q1.front()<q2.front())
{
now+=q1.front();
q1.pop();
}
else
{
now+=q2.front();
q2.pop();
}
}
cost+=now;
if(cost>t)
return 0;
q2.push(now);
}
return cost<=t;
}
int main()
{
int i,T;
cin>>T;
while(T--)
{
cin>>n>>t;
for(i=0;i<n;i++)
{
scanf("%lld",&a[i]);
}
sort(a,a+n);
int l=2,r=n,mid;
while(l<=r)
{
mid=(l+r)>>1;
if(check(mid))
{
r=mid-1;
}
else
{
l=mid+1;
}
}
printf("%d\n",r+1);
}
}