Sort---hdu5884(优先队列+二分)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5884

题意:有n个有序序列,每个序列有ai个元素,现在有一个程序每次可以归并最多k个序列,最终把所有的序列合并成一个,每次归并所需要的代价是所有序列的长度和;

现有一个代价界限T,就是总的代价不能超过T,求符合条件的最小的K;

当给定一个K的准确值时,我们可以每次选择最小的k个数进行合并;所以我们可以用优先队列来处理,但是由于范围比较大,可以优化一下,只让合并形成的序列进入优先队列,每次取数组和队列中较小的一个即可;

对于k可以用二分的方法来求,但是会发现当n=5,k=4的时候,当直接运用上面的做法,最后没有k个数,那么就不能保证单调性了,为了保证每次都是k个序列进行合并,我们可以运用补0的方法进行处理,这样就保证了二分的正确性;

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<queue>
#include<set>
using namespace std;
#define met(a, b) memset(a, b, sizeof(a))
#define N 100005
#define INF 0x3f3f3f3f
typedef long long LL;

int M, n, a[N], sum[N];

bool Judge(int k)
{
    int r = (n-k)%(k-1), Index;
    LL s;
    if(r == 0)///如果已经满足每次都是k个数了,直接取数组的前k项即可;
    {
        s = sum[k];
        Index = k+1;
    }
    else///否则就先把前r+1个数进行合并;
    {
        s = sum[r+1];
        Index = r+2;
    }
    priority_queue<LL>Q;
    Q.push(s);

    while(!Q.empty() || Index <= n)
    {
        if(Index > n && Q.size() == 1) break;///当只剩下队列中的一个数时,说明已经合并完成了;

        int cnt = 0; LL part = 0;
        while(cnt<k && (!Q.empty() || Index<=n))
        {
            if(Index <=n && (Q.empty() || a[Index] <= Q.top()))
                part += a[Index++];
            else
            {
                part += Q.top();
                Q.pop();
            }
            cnt++;
        }
        s += part;
        if(s > M) break;

        Q.push(part);
    }
    return s<=M;
}

int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        met(a, 0);
        met(sum, 0);

        scanf("%d %d", &n, &M);

        for(int i=1; i<=n; i++)
            scanf("%d", &a[i]);

        sort(a, a+n+1);
        for(int i=1; i<=n; i++)
            sum[i] = sum[i-1] + a[i];

        int L = 2, R = n, ans = 2;
        while(L <= R)
        {
            int Mid = (L+R)/2;
            if(Judge(Mid))
            {
                R = Mid - 1;
                ans = Mid;
            }
            else
                L = Mid + 1;
        }
        printf("%d
", ans);
    }
    return 0;
}
/*
5 15
0 0 0 0 0
*/
View Code
原文地址:https://www.cnblogs.com/zhengguiping--9876/p/5888702.html