HDU 5884 Sort

二分,验证。

二分$k$,然后进行验证。有一个地方需要注意一下:如果$n$个数,每次合并$k$个,最后一次不能合$k$个,那么一开始需要补$0$之后再合并才是最优的。合并的时候用优先队列合并时间复杂度过高,可以用两个队列模拟一下,优化掉一个$log$。

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<iostream>
using namespace std;
typedef long long LL;
const double pi=acos(-1.0),eps=1e-6;
void File()
{
    freopen("D:\in.txt","r",stdin);
    freopen("D:\out.txt","w",stdout);
}
template <class T>
inline void read(T &x)
{
    char c=getchar(); x=0;
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) {x=x*10+c-'0'; c=getchar();}
}

const int maxn=100010;
int n,T,k,a[maxn];

bool check(int x)
{
    queue<LL>Q[2];
    for(int i=1;i<=n;i++) Q[0].push(a[i]);

    int sz=n; LL sum=0,m0=a[n],m1=0;

    if(n%(k-1)==1){}
    else
    {
        int num; if(n%(x-1)==0) num=x-1; else num=n%(x-1);

        LL c=0;
        for(int i=1;i<=num;i++)
        {
            c=c+Q[0].front(); Q[0].pop();
        }

        sum=sum+c;
        if(sum>k) return 0;

        Q[1].push(c); m1=c;

        sz=sz-num+1;
    }

    if(sz==1)
    {
        if(sum>k) return 0;
        return 1;
    }

    while(1)
    {
        LL c=0;
        for(int i=1;i<=min(sz,x);i++)
        {
            if((!Q[0].empty())&&(!Q[1].empty()))
            {
                if(Q[0].front()<Q[1].front()) { c=c+Q[0].front(); Q[0].pop(); }
                else { c=c+Q[1].front(); Q[1].pop(); }
            }
            else if(!Q[0].empty()) { c=c+Q[0].front(); Q[0].pop(); }
            else { c=c+Q[1].front(); Q[1].pop(); }
        }

        sum=sum+c;
        if(sum>k) return 0;

        if(Q[0].empty()) { Q[0].push(c); m0=c; }
        else if(Q[1].empty()) { Q[1].push(c); m1=c; }
        else
        {
            if(c>=m0) { Q[0].push(c); m0=c; }
            else if(c>=m1) { Q[1].push(c); m1=c; }
        }

        if(sz<=x) break;

        sz=sz-x+1;
    }

    if(sum>k) return 0;
    return 1;
}

int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        sort(a+1,a+1+n);
        int L=2,R=n,ans;
        while(L<=R)
        {
            int m=(L+R)/2;
            if(check(m)) ans=m,R=m-1;
            else L=m+1;
        }
        printf("%d
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/zufezzt/p/5886993.html