Bootstrap

多重背包二进制分组优化

tty 的求助 2
【问题描述】
“唐诗”的好朋友**特别喜欢购物,一天,她拉着土豪 tty 去购物。她选中 了 n 种商品,第 i 种商品有库存 ai,购买一件商品 i,tty 会获得“唐诗”的好朋 友的好感度 bi,第 i 件商品的质量为 wi。 由于 tty 是土豪,所以他不用考虑钱不够的问题。但是 tty 的力气不大,所 以他只能提起质量不大于 m 千克的商品。tty 想知道他最多能获得多少好感度。 对于 OI 大神 tty 来说,这样的题目显然很简单,但是他身边没有电脑,所 以他只能再次向同为大神的你求助。
【输入格式】
在输入文件 help.in 中,共有 n+1 行。 第一行为两个数 n,m。 后接 n 行,每行 3 个数,第 i 行为 ai,bi,wi。
【输出格式】
在输出文件 help.out 中,有一个数,为 tty 最多获得的好感度。
【样例输入】
3 10

2 3 4

1 4 3

2 5 3
【样例输出】
14
【数据规模与约定】
测试点 数据规模 1~2 n≤5,m≤100,ai≤5 3~5 n≤100,m≤1000,ai≤100 6~10 n≤100,m≤20000,ai≤5000 对于 100%的数据保证 bi 在 int 范围内,wi≤100

这道题显然是一道多重背包,考虑到数据范围,我们应该对O(anm)的复杂度进行优化。

因为有多个相同的物品,我们可以发现, a个相同的物品可以当成1+2+...+2^k+x,共k+1种不同的物品,其中x小于2^(k+1), 这样可以把 a 次重复计算化简为 loga 次。

然后再用dp求解就行了。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 100000;
const int MAXM = 20000;
typedef long long LL;
typedef double DB;
inline int get(){
	char c;
	while((c = getchar()) < '0' || c > '9');
	int cnt = c - '0';
	while((c = getchar()) >= '0' && c <= '9') cnt = cnt * 10 + c - '0';
	return cnt;
}
int N,M;
int b[MAXN + 10],w[MAXN +10],a,tot;
int f[MAXM + 10];
int main(){
	#ifdef lwy
		freopen("1.txt","r",stdin);
	#else
		freopen("help.in","r",stdin);
		freopen("help.out","w",stdout);
	#endif
	N = get(); M = get();
	tot = 0;
	for(int i = 1; i <= N; i ++){
		a = get(); b[++tot] = get(); w[tot] = get();
		int b1 = b[tot], w1 = w[tot]; 
		a --;
		int nown = 2;
		while(1){
			if(a >= nown){
				a -= nown;
				b[++tot] = b[tot - 1] * 2;
				w[tot] = w[tot - 1] * 2;
			}
			else{
				b1 = a * b1;
				w1 = a * w1;
				b[++tot] = b1;
				w[tot] = w1;
				break; 
			}
			nown *= 2;
		}
	}
	memset(f,0,sizeof(f));
	for(int i = 1; i <= tot; i ++){
		for(int j = M; j >= w[i]; j --){
			f[j] = max(f[j],f[j - w[i]] + b[i]);
		}
	}
	printf("%d",f[M]);
	return 0;
}





;