题解 [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;
}
谢谢大家!如有错误,欢迎批评指正!

浙公网安备 33010602011771号