砝码从小到大放最优,二分答案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; }