1190: [HNOI2007]梦幻岛宝珠
我们对b分层,对于每一层用a背包,然后考虑如何在层之间转移。
F[i]表示还剩余i空间的最优解,略有不同,然后就直接从上一层j转移到j*2+(W这一位是否为1)。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,W,A;long long f[2][1005],Ans;
struct xcw{int a,b,v;bool operator <(const xcw c)const{return b>c.b;};}a[105];
void Work(){
int now=1,lst=0;f[lst][0]=0;
for(int i=30,k=1;i>=0;i--,now^=1,lst^=1){
memset(f[now],192,sizeof(f[now]));
for(int j=0,x;j<=1000;j++) x=min((j<<1)+((W>>i)&1),1000),f[now][x]=max(f[now][x],f[lst][j]);
for(;k<=n&&a[k].b==i;k++)
for(int j=a[k].a;j<=1000;j++) f[now][j-a[k].a]=max(f[now][j-a[k].a],f[now][j]+a[k].v);
}
for(int i=0;i<=1000;i++) Ans=max(Ans,f[lst][i]);
}
int main(){
while(1){
memset(f,192,sizeof(f));memset(a,0,sizeof(a));Ans=0;
scanf("%d%d",&n,&W);
if(n==-1) break;
for(int i=1;i<=n;i++){
int w,v;scanf("%d%d",&w,&v);
while(!(w&1)) a[i].b++,w>>=1;a[i].a=w;a[i].v=v;
while(a[i].b>30) a[i].a<<=1,a[i].b--;
}
sort(a+1,a+1+n);
Work();
printf("%lld\n",Ans);
}
return 0;
}