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;
}