正解
要使得包正好充满,无法再放入其他的物品,我们不妨考虑枚举正好塞不下的物品是哪一件,即
剩下不拿的物品里面最小的物品是哪一件。
可以发现,因为正好放不进去的物品满足是不拿的物品里面最小的物品,所以比这个物品小的,肯定全部要塞下去,然后剩下比他大的物品,显然就是我们经典的(0/1)背包的做法。
有个坑点是,所有的物品都放下了,背包还是没有溢出,按照题意,这算是一种方案。
代码
#include<bits/stdc++.h>
using namespace std;
using LL=long long;
LL f[100005],a[5005];
int main() {
LL T;
scanf("%lld",&T);
while(T--) {
LL sum=0;
memset(f,0,sizeof(f)),f[0]=1;
LL n,m;
scanf("%lld %lld",&n,&m);
for(LL i=1; i<=n; i++) {
scanf("%lld",a+i),sum+=a[i];
}
if(sum<=m) {
printf("1
");
continue;
}
sort(a+1,a+1+n);
LL ans=0;
for(LL i=n; i; i--) {
int k=sum-a[i]-m;
k=max(k,0);
for(int j=k; j<sum-m; j++) {//每局第一个装不下的酒
ans+=f[j];
}//比这个物品小的,肯定全部要塞下去(区间对应
for(int j=sum; j>=a[i]; j--) {
f[j]+=f[j-a[i]];
}//比它大的,可以加上它的酒量。
}
printf("%lld
",ans);
}
return 0;
}