BZOJ1110 : [POI2007]砝码Odw

砝码从小到大放最优,二分答案mid,转化为判定前mid小的砝码能否放完。

从大到小考虑砝码,依次扫描每个容器,能放就放。

由于砝码重量都成倍数关系,所以最多只有$O(log n)$种不同的数字,所以总复杂度为$O(nlog^2n)$。

#include<cstdio>
#include<algorithm>
#define N 100010
int n,m,i,j,k,t,a[N],b[N],c[N],l,r,mid,ans;
inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
bool check(int x){
  for(i=1;i<=n;i++)c[i]=a[i];
  for(;x;x=j){
    for(j=x-1;b[x]==b[j];j--);
    for(t=x-j,i=1;i<=n&&t;i++){
      k=c[i]/b[x];
      if(k>t)k=t;
      c[i]-=k*b[x],t-=k;
    }
    if(t)return 0;
  }
  return 1;
}
int main(){
  read(n),read(m);
  for(i=1;i<=n;i++)read(a[i]);
  for(i=1;i<=m;i++)read(b[i]);
  std::sort(b+1,b+m+1),l=1,r=m;
  while(l<=r)if(check(mid=(l+r)>>1))l=(ans=mid)+1;else r=mid-1;
  return printf("%d",ans),0;
}

  

原文地址:https://www.cnblogs.com/clrs97/p/4614599.html