zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    Tempter of the Bone 搜索---奇偶性剪枝
    uestc 1709 Binary Operations 位运算的灵活运用
    uestc 1072 a ^ b
    uestc Another LCIS
    武汉邀请赛 Key Logger 双向链表
    bnu 29378 Adidas vs Adivon 基础题
    中南月赛F ZZY and his little friends
    日期问题
    开灯问题
    开灯问题
  • 原文地址:https://www.cnblogs.com/zhengguiping--9876/p/5888702.html
Copyright © 2011-2022 走看看