ACM模版

描述

题解

这个题十分有趣,二分 + 贪心。

二分 k ,然后贪心判定是否可以通过。这里判断的过程可以用优先队列优化,每次出 k 个小的,然后合并起来,变为一个大的存入,但是这样会超时,也许用输入输出外挂可以卡过,但是这里有更好的办法,就是用两个队列,先排序将序列进队列 qi1 ,然后每次从 qi1qi2 中取前 k 个最小值,合并后直接入 qi2 ,这里很容易证明每次入 qi2 的值都比之前入的大,一直到 qi1 为空, qi2 只剩下一个元素时,结束。

这里有一个很大很大的坑,假如枚举的 k ,那么每次合并消耗的是 k1 个,最后合并完后剩下一个,所以总消耗是 n1 个,那么问题来了,如果 (n1) ,会存在零头,也就是说凑不够 k 个,这个零头怎么办呢?肯定不能放在最后合并,我们应该将这个零头放在开头合并,取这零头个数进行合并,也就是取这最小的几个进行合并,后边的就没有什么问题了,按照上边讲的搞就行了。

题猛一看很简单,也能用很简单的手段过,但是这个坑点一般容易忽视,需要特别注意。

代码

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>

using namespace std;

const int MAXN = 1e5 + 10;

int N, T;
int a[MAXN];
queue<int> qi1, qi2;

bool charge(int k)
{
    while (!qi1.empty())
    {
        qi1.pop();
    }
    while (!qi2.empty())
    {
        qi2.pop();
    }
    for (int i = 1; i <= N; i++)
    {
        qi1.push(a[i]);
    }

    int num = 0, sum = 0, ans = 0;
    if ((N - 1) % (k - 1) != 0)
    {
        num = (N - 1) % (k - 1) + 1;
        for (int i = 1; i <= num; i++)
        {
            sum += qi1.front();
            qi1.pop();
        }
        qi2.push(sum);
        ans += sum;
    }

    while (!qi1.empty())
    {
        sum = 0;
        for (int i = 1; i <= k; i++)
        {
            if (!qi1.empty() && !qi2.empty())
            {
                if (qi1.front() <= qi2.front())
                {
                    sum += qi1.front();
                    qi1.pop();
                }
                else
                {
                    sum += qi2.front();
                    qi2.pop();
                }
            }
            else if (!qi1.empty())
            {
                sum += qi1.front();
                qi1.pop();
            }
            else if (!qi2.empty())
            {
                sum += qi2.front();
                qi2.pop();
            }
        }
        ans += sum;
        qi2.push(sum);
    }
    if (ans > T)
    {
        return false;
    }

    sum = 0;
    num = 0;
    while (!qi2.empty())
    {
        sum += qi2.front();
        qi2.pop();
        num++;
        if (num == k)
        {
            qi2.push(sum);
            ans += sum;
            sum = 0;
            num = 0;
            if (qi2.size() == 1)
            {
                break;
            }
        }
    }
    if (ans > T)
    {
        return false;
    }

    return true;
}

int main()
{
    int t;
    scanf("%d", &t);

    while (t--)
    {
        scanf("%d%d", &N, &T);
        for (int i = 1; i <= N; i++)
        {
            scanf("%d", &a[i]);
        }
        sort(a + 1, a + N + 1);

        int l = 2, r = N, m, ans = 1;
        while (l <= r)
        {
            m = (l + r) >> 1;
            if (charge(m))
            {
                r = m - 1;
                ans = m;
            }
            else
            {
                l = m + 1;
            }
        }

        printf("%d\n", ans);
    }

    return 0;
}