P3188 [HNOI2007] 梦幻岛宝珠
标签:DP) \(C\)
容易想到按 \(b_i\) 给物品分组。
对每个组跑背包,设 \(f_{i,j}\) 表示只考虑重量为 \(a \times 2^i\) 的物品,用 \(j × 2^i\) 的体积装的最大价值,这个显然是 01 背包 板子。
然后考虑背包的合并,设 \(g_{i,j}\) 表示考虑重量为 \(a \times 2^0 \sim a \times 2^i\) 的物品,用了 \(j × 2^i + m\&(2^i − 1)\) 的体积的最大价值,转移同样是显然的。
#include<bits/stdc++.h>
using namespace std;
const int NN = 108;
int n,m;
int num[32];
int a[32][NN];
int w[32][NN];
int f[32][1008];
int g[32][1008];
inline int read(){
int res = 0,flag = 1;
char c = getchar();
while(!isdigit(c)){
if(c == '-') flag = -1;
c = getchar();
}
while(isdigit(c))
res = res * 10 + c - '0',c = getchar();
return res * flag;
}
void init(){
memset(a,0,sizeof(a));
memset(num,0,sizeof(num));
memset(w,0,sizeof(w));
memset(f,0,sizeof(f));
memset(g,0,sizeof(g));
}
int main(){
n = read(); m = read();
while(n != -1 && m != -1){
init();
for(int i = 1; i <= n; ++i){
int x = read();
int cnt = 31;
while(x & ((1 << (--cnt)) - 1));
a[cnt][++num[cnt]] = x / (1 << cnt);
w[cnt][num[cnt]] = read();
}
int cnt = 31;
while(m <= (1 << (--cnt)));
for(int t = 0; t <= cnt; ++t)
for(int i = 1; i <= num[t]; ++i)
for(int j = 10 * num[t]; j >= a[t][i]; --j)
f[t][j] = max(f[t][j],f[t][j - a[t][i]] + w[t][i]);
for(int j = 0; j <= 10 * num[0]; ++j)
g[0][j] = f[0][j];
for(int i = 1; i <= cnt; ++i)
for(int j = 0; j <= 10 * n; ++j)
for(int k = 0; k <= j; ++k)
g[i][j] = max(g[i][j],f[i][j - k] + g[i - 1][min(10 * n,k * 2 + ((m >> (i - 1)) & 1))]);
printf("%d\n",g[cnt][1]);
n = read(),m = read();
}
}
本文来自博客园,作者:ricky_lin,转载请注明原文链接:https://www.cnblogs.com/rickylin/p/-/solution_P3188

浙公网安备 33010602011771号