luogu3188/bzoj1190 梦幻岛宝珠 (分层背包dp)
Posted ressed
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luogu3188/bzoj1190 梦幻岛宝珠 (分层背包dp)相关的知识,希望对你有一定的参考价值。
他都告诉你能拆了 那就拆呗。把每个重量拆成$a*2^b$的形式
然后对于每个不同的b,先分开做30个背包
再设f[i][j]表示b<=i的物品中 容量为$ j*2^i+W&((1<<(i-1))-1) $(就是这一位是j+W的前i-1位)的最大权值(这个容量没必要填满)
然后f[i][j]就可以从f[i-1][j*2+W的第i-1位]转移过来,再拿着这个去更新本层的其他容量
最后答案就是f[x][1],x是W的最高位1的位数
1 #include<bits/stdc++.h> 2 #define pa pair<int,int> 3 #define CLR(a,x) memset(a,x,sizeof(a)) 4 using namespace std; 5 typedef long long ll; 6 const int maxn=110,maxs=1e3+10,maxp=33; 7 8 inline ll rd(){ 9 ll x=0;char c=getchar();int neg=1; 10 while(c<‘0‘||c>‘9‘){if(c==‘-‘) neg=-1;c=getchar();} 11 while(c>=‘0‘&&c<=‘9‘) x=x*10+c-‘0‘,c=getchar(); 12 return x*neg; 13 } 14 15 int N,W,sum[maxs];ll f[maxp][maxs]; 16 17 int main(){ 18 //freopen(".in","r",stdin); 19 int i,j,k; 20 while(1){ 21 N=rd(),W=rd(); 22 if(N==-1) break; 23 CLR(f,0);CLR(sum,0); 24 int x=log2(W); 25 for(i=1;i<=N;i++){ 26 int a=rd(),b=0,v=rd(); 27 while(a&&a%2==0) b++,a>>=1; 28 if(b>x) continue; 29 for(j=min(sum[b],1000-a);j>=0;j--){ 30 f[b][j+a]=max(f[b][j+a-1],max(f[b][j+a],f[b][j]+v)); 31 } 32 sum[b]+=a; 33 } 34 35 for(i=0;i<x;i++){ 36 for(j=1;j<=1000;j++) f[i][j]=max(f[i][j-1],f[i][j]); 37 for(k=1000;k>=0;k--){ 38 if(k&&!f[i+1][k]) continue; 39 for(j=1000;j>=k;j--){ 40 f[i+1][j]=max(f[i+1][j],f[i+1][k]+f[i][min(1000,2*(j-k)+((W>>i)&1))]); 41 } 42 } 43 } 44 printf("%lld ",f[x][1]); 45 } 46 return 0; 47 }
以上是关于luogu3188/bzoj1190 梦幻岛宝珠 (分层背包dp)的主要内容,如果未能解决你的问题,请参考以下文章
bzoj1190--梦幻岛宝珠--分层dp+01背包(未完成)