luogu P3423 [POI2005]BAN-Bank Notes
Byteotian Bit Bank (BBB) 拥有一套先进的货币系统,这个系统一共有n种面值的硬币,面值分别为b1, b2,…, bn. 但是每种硬币有数量限制ci,现在我们想要凑出面值k求最少要用多少个硬币.
n<=200,bi<=20000,ci<=20000
还要输出方案。。。。
这道题第一眼多重背包,然后打了 ,65分,开O2 70分。。
我们可以换个思路,何必枚举每种货币选多少个,每次只拿一个,只要记录一下前面状态拿了多少个,判断还有没有剩余就好了。
当然,第一维for循环不再是枚举货币,而是面值。
你要用单调队列,二进制拆分也没人拦你QAQ
Code
#include<iostream> #include<cstdio> #include<cstring> #define R register using namespace std; int n,k,b[210],c[210],cnt[210][20010],f[20010],ans[210]; inline int read(){ char c=getchar();int x=0,flag=1; while(c<'0' || c>'9'){if(c=='-') flag=-1;c=getchar();} while(c>='0' && c<='9') x=(x<<1)+(x<<3)+c-'0',c=getchar(); return x*flag; } int main(){ n=read(); for(R int i=1;i<=n;i++) b[i]=read(); for(R int i=1;i<=n;i++) c[i]=read(); k=read(); memset(f,0x3f,sizeof(f));f[0]=0; for(R int i=1;i<=k;i++){ int val=0; for(R int j=1;j<=n;j++){ if(i>=b[j]){ if(f[i]>f[i-b[j]]+1 && cnt[j][i-b[j]]<c[j]){ f[i]=f[i-b[j]]+1;val=j; } } } cnt[val][i]=cnt[val][i-b[val]]+1; for(R int j=1;j<=n;j++) if(j!=val) cnt[j][i]=cnt[j][i-b[val]]; } printf("%d\n",f[k]); for(R int i=1;i<=n;i++) printf("%d ",cnt[i][k]);return 0; }