题面
原题链接
简要题解
这题就是一个大号01背包,所有的物品的体积均可以表示成
a
×
2
b
a \times 2^b
a×2b
我们可以考虑对于每个不同的b, 设一个
d
p
dp
dp 式
F
[
i
]
[
j
]
F[i][j]
F[i][j], 处理出当
b
=
=
i
b == i
b==i 时,
Σ
a
\Sigma a
Σa为
j
j
j 的最大价值,这一步相当于一个普通的
01
01
01 背包
考虑不同的
b
b
b 之间的转化:存在一个
b
=
=
t
b == t
b==t, 考虑从
t
−
1
t - 1
t−1 到
t
t
t 的迭代, 我们设计一个
d
p
dp
dp 式
G
[
i
]
[
j
]
G[i][j]
G[i][j] , 表示当处理了
b
∈
[
0
,
i
]
b \in [0, i]
b∈[0,i] 时, 当
b
=
i
b = i
b=i时
Σ
a
=
j
\Sigma a = j
Σa=j的最大价值, 即:
G
[
i
]
[
j
]
=
m
a
x
(
F
[
i
]
[
j
−
k
]
+
G
[
i
−
1
]
[
m
i
n
(
10
×
n
,
k
×
2
+
(
W
>
>
(
i
−
1
)
)
&
1
)
]
)
G[i][j] = max(F[i][j - k] + G[i - 1][min(10 \times n, k \times 2 + (W >> (i - 1)) \& 1)])
G[i][j]=max(F[i][j−k]+G[i−1][min(10×n,k×2+(W>>(i−1))&1)])
此式子表示,当处理到
b
=
=
i
b == i
b==i 时,在此位的
Σ
a
=
j
\Sigma a = j
Σa=j,此时取出一些空间大小为
k
k
k 退位到低位来使用,再加上前
i
−
1
i - 1
i−1位所占有的空间
W
>
>
(
i
−
1
)
)
&
1
)
]
W >> (i - 1)) \& 1)]
W>>(i−1))&1)],而剩下的
j
−
k
j - k
j−k, 就是在第
i
i
i 位进行使用,最优方案即为
F
[
i
]
[
j
−
k
]
F[i][j - k]
F[i][j−k]。
Code
#include<bits/stdc++.h>
using namespace std;
const int N = 33;
const int M = 1222;
long long F[N][M], G[N][M];
long long w[N][M / 10], v[N][M / 10], num[N];
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define repd(i,a,b) for(int i=a;i>=b;i--)
bool work(){
int n, W;
cin >> n >> W;
memset(F, 0, sizeof(F));
memset(G, 0, sizeof(G));
memset(w, 0, sizeof(w));
memset(v, 0, sizeof(v));
memset(num, 0, sizeof(num));
if(n == -1 && W == -1) return false;
rep(i, 1, n){
int x; cin >> x;
int tmp = 31;
while(x % (1ll << (--tmp)));
w[tmp][++num[tmp]] = x / (1 << tmp);
cin >> v[tmp][num[tmp]];
}
int m = 31;
while(W <= (1 << (--m)));
rep(i, 0, m){
rep(j, 1, num[i]){
repd(k, 10 * num[i], w[i][j]){
F[i][k] = max(F[i][k], F[i][k - w[i][j]] + v[i][j]);
}
}
}
rep(i, 0, 10 * num[0]) G[0][i] = F[0][i];
rep(i, 1, m){
rep(j, 0, 10 * n){
rep(k, 0, j){
G[i][j]=max(G[i][j],F[i][j-k]+G[i-1][min(10*n,k*2+((W>>(i-1))&1))]);
}
}
}
cout<<G[m][1]<<endl;
return true;
}
int main(){
ios::sync_with_stdio(false);
while(work());
}