梦幻岛宝珠「HNOI2007」
题意
给\(n\)个宝石,每个宝石都有重量与价值,求总重量不超过\(W\)时的最大价值。\(W\leq 2^{32}\)
保证每个宝石的重量都可以被表示为\(a*2^b\)的形式。
思路
分组背包,对\(b\)分组,在每一组内跑01背包。
每一组之间的转移有\(f[i][j]=max(f[i][j],f[i][k]+f[i-1][min(1000,(j-k)<<1)+((W>>(i-1))&1)])\)
代码
#include <bits/stdc++.h>
using namespace std;
namespace StandardIO {
template<typename T> inline void read (T &x) {
x=0;T f=1;char c=getchar();
for (; c<'0'||c>'9'; c=getchar()) if (c=='-') f=-1;
for (; c>='0'&&c<='9'; c=getchar()) x=x*10+c-'0';
x*=f;
}
template<typename T> inline void write (T x) {
if (x<0) putchar('-'),x=-x;
if (x>=10) write(x/10);
putchar(x%10+'0');
}
}
using namespace StandardIO;
namespace Solve {
const int N=1001;
int n,W,ans;
int w[N],v[N];
int f[N][N];
inline void MAIN () {
while (1) {
read(n),read(W);
if (n==-1) return;
memset(f,0,sizeof(f)),ans=0;
for (register int i=1; i<=n; ++i) {
read(w[i]),read(v[i]);
int b=0,a=w[i];
while (!(a&1)) a>>=1,++b;
for (register int j=min(1000,W>>b); j>=a; --j) {
f[b][j]=max(f[b][j],f[b][j-a]+v[i]);
ans=max(ans,f[b][j]);
}
}
for (register int i=1; (1<<i)<W; ++i) {
for (register int j=min(1000,W>>i); j>=0; --j) {
for (register int k=j; k>=0; --k) {
f[i][j]=max(f[i][j],f[i][k]+f[i-1][min(1000,(j-k)<<1ll)+((W>>(i-1))&1ll)]);
ans=max(ans,f[i][j]);
}
}
}
write(ans),putchar('\n');
}
}
}
int main () {
Solve::MAIN();
}