题目链接: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 ",++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 ",++cas,i); break; } } return 0; }