Recently, Bob has just learnt a naive sorting algorithm: merge sort. Now, Bob receives a task from Alice.
Alice will give Bob N sorted sequences, and the i-th sequence includes ai elements. Bob need to merge all of these sequences. He can write a program, which can merge no more than k sequences in one time. The cost of a merging operation is the sum of the length of these sequences. Unfortunately, Alice allows this program to use no more than T cost. So Bob wants to know the smallest k
to make the program complete in time.
Input
The first line of input contains an integer t0
, the number of test cases. t0 test cases follow.
For each test case, the first line consists two integers N (2≤N≤100000) and T (∑Ni=1ai<T<231).
In the next line there are N integers a1,a2,a3,...,aN(∀i,0≤ai≤1000)
.
Output
For each test cases, output the smallest k
.
Sample Input
1 5 25 1 2 3 4 5
Sample Output
3
K叉哈夫曼树
难点: 如果叶子不够所有的枝都是K叉,怎样来处理
考虑 树的节点数量 = 所有点的出度 + 1 , 这里的出度仅是儿子方向的
一棵 满K叉树, 一共两种节点 出度为1 和 出度为k的,得 (设K叉节点的个数为star)
得到 , 所以说如果满足这个关系式的话,可以直接满K叉树;
那不满我们应该怎么办?
我们拿下来几个,让剩下的正好组成满K叉树,因为大的总要靠近树根,所以考虑余下的,我们拿最下面的叶子,那么拿几个呢?
我们可能会考虑拿掉 个,但是这样是不对的,我们不是真的拿掉,而是对于这些余数特殊的合并,所以我们考虑在满K叉树的叶子上再拿下来一个节点,然后用 这个叶子来存储,这些余数的总和,所以我们 需要拿掉 个节点下来
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define rep(i,a,b) for(int i=a;i<b;i++)
const LL inf=1e18;
const int N=1e5+10;
LL val[N];
struct Queue{
int head,tail;
int len;
LL elem[N];
Queue(int _head=0,int _tail=0,int _len=0){
head=_head,tail=_tail,len=_len;
}
void push(LL x){
++len; elem[tail]=x;tail=(tail+1)%N;
}
int pop(){
--len; LL x=elem[head];head=(head+1)%N;
return x;
}
};
/*
实现的问题:O(n)
设置两个队列,一个存储排好序的原数组,一个为空(有剩余的时候,里面放着剩余的)
我们一直都是按照从前面取K个数的,所以第二个队列后面的数一定会比前面的数大,所以不停的比较就好了
*/
LL sum;
int check(int x,int n){
Queue q1,q2;
LL ans=0;
int m=(n-1)%(x-1);
if(m){
++m;
for(int i=1; i<=m; i++) ans+=val[i];
q2.push(ans);//!!!别忘了,WA到死
}
rep(i,m+1,n+1) q1.push(val[i]);
int up=(n-1)/(x-1);
rep(i,0,up){
int num=x;
LL tmp=0;
while(num--){
LL tmp1=inf,tmp2=inf;
if(q1.len) tmp1=q1.elem[q1.head];
if(q2.len) tmp2=q2.elem[q2.head];
if(tmp1<tmp2){
tmp+=tmp1;
q1.pop();
}
else{
tmp+=tmp2;
q2.pop();
}
}
ans+=tmp;
q2.push(tmp);
}
return ans<=sum;
}
int main(){
int T;
scanf("%d",&T);
while(T--){
int n;
scanf("%lld %lld",&n,&sum);
for(int i=1; i<=n; i++){
scanf("%lld",&val[i]);
}
sort(val+1,val+n+1);
int l=2,r=n,mid,ans=n;
while(l<=r){
mid=(l+r)>>1;
if(check(mid,n)){
ans=mid;
r=mid-1;
}
else
l=mid+1;
}
printf("%d\n",ans);
}
return 0;
}
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define rep(i,a,b) for(int i=a;i<b;i++)
const LL inf=1e18;
const int N=1e5+10;
LL val[N];
struct Queue{
int head,tail;
int len;
LL elem[2*N];
Queue(int _head=0,int _tail=0,int _len=0) {
head=_head,tail=_tail,len=_len;
}
void push(LL x){
++len;
elem[tail]=x;
tail=(tail+1)%N;
}
int pop(){
--len;
LL x=elem[head];
head=(head+1)%N;
return x;
}
};
LL sum;
int check(int x,int n){
// printf(" x:%d n:%d\n",x,n);
priority_queue<LL,vector<LL>,greater<LL> > q;
Queue q1,q2;
LL ans=0;
int m=(n-1)%(x-1);
if(m){
++m;
for(int i=1; i<=m; i++) ans+=val[i];
q.push(ans);
}
//rep(i,m+1,n+1) q1.push(val[i]);
rep(i,m+1,n+1) q.push(val[i]);
int up=(n-1)/(x-1);
// printf("up:%d m:%d\n",up,m);
rep(i,0,up){
int num=x;
LL tmp=0;
while(num--){
tmp+=q.top();
q.pop();
}
ans+=tmp;
q.push(tmp);
}
//printf("x:%d ans:%lld\n",x,ans);
return ans<=sum;
}
int main()
{
int T;
scanf("%d",&T);
//read(T);
while(T--){
int n;
//read(n);read(sum);
scanf("%d %lld",&n,&sum);
for(int i=1; i<=n; i++)
{
scanf("%lld",&val[i]);
//read(val[i]);
}
sort(val+1,val+n+1);
int l=2,r=n,mid,ans=n;
while(l<=r){
mid=(l+r)>>1;
if(check(mid,n)){
ans=mid;
r=mid-1;
}
else
l=mid+1;
}
printf("%d\n",ans);
// print(ans);
}
return 0;
}