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;
}

 

posted @ 2019-10-14 11:54  dzzx_Syh  阅读(148)  评论(0编辑  收藏  举报