【GOJ 3015】疯狂外星人

题目

正解

要使得包正好充满,无法再放入其他的物品,我们不妨考虑枚举正好塞不下的物品是哪一件,即
剩下不拿的物品里面最小的物品是哪一件。

可以发现,因为正好放不进去的物品满足是不拿的物品里面最小的物品,所以比这个物品小的,肯定全部要塞下去,然后剩下比他大的物品,显然就是我们经典的(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;
}
原文地址:https://www.cnblogs.com/Sam2007/p/13398450.html