这题的正确性就很神奇
给若干个矩形的宽,高都是1,给每层的限定宽度,问最少多少层。
一般的想法就是每层都尽量填,一直到填不下去为止。
一种做法是搞一个multiset 然后遍历每个矩形,往最大的那个层丢,不行就开新层
还有一种做法是,设一层 二分找能丢进去的矩形,直到不能丢进去,然后再设新层,新丢进去,直到搞完。
还有一种做法是 开log2的桶,每次遍历,反复操作
void solve(){ cin>>n>>w; multiset<int,greater<int> >s; s.insert(w); for(int i=1;i<=n;++i){ cin>>a[i]; } sort(a+1,a+1+n,greater<int>()); for(int i=1;i<=n;++i){ int x=*s.begin(); if(x>=a[i]){ s.insert(x - a[i]); s.erase(s.find(x)); } else{ s.insert(w-a[i]); } } cout<<s.size()<<" "; }
int n,w,cnt[100],x; void solve(){ memset(cnt,0,sizeof(cnt)); cin>>n>>w; for(int i=1;i<=n;++i){ cin>>x; int y=log2(x); cnt[y]++; } int ans=0; while(n){//n块 ans++; x=w; for(int i=40;i>=0;--i){ int now=pow(2,i); while(cnt[i]&&x>=now){//当前桶有东西且剩余量够 cnt[i]--;n--; x=x-now; } } } cout<<ans<<" "; }
关于正确性,确实很神奇
因为这题都是2的倍数
所以比如举个例子 8+4+4+2+1>16,那么16一定可以被拆成8+4+4
也就是说一定可以被拆成前缀
好,那么假设最优解 为A,我们的贪心解为B
对每层的块从大到小排序
如果B的第一块<A的第一块 不可能,因为我们是贪心取的
如果B的第一块>A的第一块 那么A中再加上后面的几块,
若加上还小,说明正好多出来几个小块,不能被归并到其他层,贪心解还是正确的
若加上后大于等于 ,则进行前缀和替换,不影响最优性
如果B的第一块==A的第一块,好,那么就是最优的
不是2的倍数不成立
6 13
6 6 4 4 3 3
贪心解中6不能被4 3 替换