G - Sort HDU - 5884(K叉哈夫曼树)

版权声明:小白一个,欢迎各位指错。 https://blog.csdn.net/qq_36424540/article/details/82154697

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的,得  \bg_white \bigstar +N =\bigstar *K +1 (设K叉节点的个数为star)

得到 N - 1 =\bigstar*(K-1), 所以说如果满足这个关系式的话,可以直接满K叉树;

那不满我们应该怎么办?

我们拿下来几个,让剩下的正好组成满K叉树,因为大的总要靠近树根,所以考虑余下的,我们拿最下面的叶子,那么拿几个呢?

我们可能会考虑拿掉(N-1) mod (K-1) 个,但是这样是不对的,我们不是真的拿掉,而是对于这些余数特殊的合并,所以我们考虑在满K叉树的叶子上再拿下来一个节点,然后用 这个叶子来存储,这些余数的总和,所以我们 需要拿掉(N-1)mod(K-1)+1 个节点下来

#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;
}

猜你喜欢

转载自blog.csdn.net/qq_36424540/article/details/82154697