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背包(未完成)

bzoj1190[HNOI2007]梦幻岛宝珠 分层背包dp

题解报告——梦幻岛的珠宝

luogu3224 永无乡(动态开点,权值线段树合并)

Luogu P3393 逃离僵尸岛

Luogu P3393 逃离僵尸岛最短路By cellur925