2019牛客暑期多校训练营(第六场)-D Move

题目链接:https://ac.nowcoder.com/acm/contest/886/D

题意:给n个物品,每个物品有一个体积值,K个箱子,问箱子的最小体积为多少可将物品全部装下。

思路:比赛时一看到题,就认定是二分,然后就wa了三小时。赛后知道这部满足二分的单调性,比如官方题解的例子:

  

   正确做法是暴力枚举即可,答案下界为sum/K,上界为sum/K+maxv。上界证明如下:

  

   对每一个答案的判断的复杂度为nlogn,所以总复杂度为O(maxv×nlogn)。

AC代码:

#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;

const int maxn=1005;
int T,n,K,cas,v[maxn];
vector<int> vc;

int work(int x){
    vc.clear();
    vc.push_back(0);
    for(int i=1;i<=n;++i)
        vc.push_back(v[i]);
    vc.push_back(0x3f3f3f3f);
    int res=0,num=0;
    while(1){
        ++res;
        int now=x,ri=vc.size()-2;
        while(1){
            int l=0,r=ri,mid;
            while(l<=r){
                mid=(l+r)>>1;
                if(vc[mid]<=now) l=mid+1;
                else r=mid-1;
            }
            if(!r) break;
            else{
                now-=vc[r];
                ++num;
                vector<int>::iterator it=vc.begin()+r;
                vc.erase(it);
                if(now<vc[1]) break;
                ri=r-1;
            }
        }
        if(num==n) break;
    }
    return res;
}

int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&K);
        int sum=0;
        for(int i=1;i<=n;++i){
            scanf("%d",&v[i]);
            sum+=v[i];
        }
        sort(v+1,v+1+n);
        if(K>=n){
            printf("Case #%d: %d\n",++cas,v[n]);
            continue;
        }
        int l=sum/K,r=sum/K+v[n];
        for(int i=l;i<=r;++i)
            if(work(i)==K){
                printf("Case #%d: %d\n",++cas,i);
                break;
            }
    }
    return 0;
}

 

posted @ 2019-08-08 11:21  Frank__Chen  阅读(205)  评论(0编辑  收藏  举报