题解 [ABC286D] Money in Hand

大家好,我是 CQ-C2024 蒟蒻 CJH。

题意

题目翻译很清楚,不懂的再回去看看题面。

分析

这是一道典型的多重背包问题。

朴素算法

注意到数据范围并不需要使用二进制分组优化,所以这里可以拆分成 0-1 背包问题求解。

时间复杂度 $O(X\sum_{i=1}^NB_i)$。

二进制拆分优化

考虑长远一点,如果 $B_i$ 的数据范围再大一点,肯定无法使用朴素算法。

我们可以使用二进制拆分优化,让复杂度降低。

时间复杂度 $O(X\sum_{i=1}^N\log_2B_i)$。

代码

朴素算法

//the code is from chenjh
#include<cstdio>
int n,x,a[55],b[55];
bool c[10001];
int main(){
    scanf("%d%d",&n,&x);
    for(int i=1;i<=n;i++) scanf("%d%d",&a[i],&b[i]);
    c[0]=1;
    for(int i=1;i<=n;i++)for(int j=1;j<=b[i];j++)for(int k=x;k>=a[i];k--)//单个拆分求解。
        c[k]|=c[k-a[i]];
    puts(c[x]?"Yes":"No");
    return 0;
}

二进制拆分优化

//the code is from chenjh
#include<cstdio>
int n,x,a[55],b[55];
bool c[10001];
int min(int x,int y){return x<y?x:y;}
int main(){
    scanf("%d%d",&n,&x);
    for(int i=1;i<=n;i++) scanf("%d%d",&a[i],&b[i]);
    c[0]=1;
    for(int i=1;i<=n;i++){
        for(int j=1;b[i]>0;j<<=1){//二进制分组优化求解。
            j=min(j,b[i]),b[i]-=j;
            for(int k=x;k>=j*a[i];k--) c[k]|=c[k-j*a[i]];
        }
    }
    puts(c[x]?"Yes":"No");
    return 0;
}

谢谢大家!如有错误,欢迎批评指正!

posted @ 2023-01-26 21:23  Chen_Jinhui  阅读(16)  评论(0)    收藏  举报  来源