题目连接:https://cn.vjudge.net/problem/HDU-5884

题意:给你n个序列,将其合并为一个,每次合并的花费为合并序列的长度的加和,先给你总花费T,保证在花费不超过T的基础上,求每次最少需要合并几个序列。

做题的时候虽然只是想到了二分+哈夫曼树,可是由于数组开小了,导致一直wa,最后发现了,改掉数组之后,立马超时

哈哈哈,果然纯2分+优先队列是不行的  需要优化。

两个数组模拟优先队列也行,

下面这样做也行

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define ll long long
#define pb push_back
using namespace std; 
const int MAXM = 100100;
const int INF = 0x3f3f3f3f;

int T, n;
ll a[MAXM],m, sum[MAXM];
priority_queue<ll,vector<ll>, greater<ll> >q;
bool f(int x) { 
    while(!q.empty())q.pop();
    ll ans=0,cnt=0,temp=0;
    int r = (n-1)%(x-1);
    if(r) {
        r++;
        q.push(sum[r]);
        ans+=q.top();
    }
    for(int i=r+1;i<=n;i++) q.push(a[i]);
    cnt = (n - 1) / (x - 1);
    while(cnt--) {
        temp = 0;
        int k = x;
        while(k--) {
            temp+=q.top();
            q.pop();
        }
        ans+=temp;
        q.push(temp);
        if(ans>m)return 0;
    }
    return ans<=m;
}
int main()
{
    scanf("%d",&T);
    while(T--) {
        sum[0] = 0;
        scanf("%d%lld", &n, &m);
        for(int i = 1;i <= n; i++) {
            scanf("%lld", &a[i]);
        }
        sort(a+1, a+n+1);
        for(int i=1;i<=n;i++) 
            sum[i] = sum[i - 1] + a[i];
        int l = 2, r = n;
        while(l<=r) {
            int mid = l + r >> 1;
            if(f(mid))
                r = mid - 1;
            else l = mid + 1;
        }
        printf("%d\n",l);
    }
    return 0;
}