传送门

注意到 $a,b$ 不大

考虑对每一个 $a*2^b$ 的 $b$ 分别背包

设 $f[i][j]$ 表示只考虑 $b=i$ 的物品时,容量为 $j= \sum a$ 的最大价值

这个就是普通的 $01$ 背包

考虑把 $f[i][j]$ 之间合并起来,为了得到容量为 $W$ 时的答案,我们要把 $f$ 的含义稍微变化一下

变成 $f[i][j]$ 表示当前考虑了 $b=2^1$ 到 $b=2^i$ 时的物品,容量为 $j*2^i$ 加上 $W$ 二进制下前 $i-1$ 位的值,此时的最大价值

考虑用 $f[i-1][]$ 更新 $f[i][j]$,枚举总体积为 $(j-k)*2^i$ 的 $b=2^i$ 的物品的最大价值($f[i][j-k]$)

加上总体积为 $2k*2^{i-1}$ 的 $b<2^i$ 的物品的最大价值 ($f[i-1][k*2]$),注意我们还要考虑 $W$ 的容积,所以设 $W$ 第 $i-1$ 位为 $p$

那么转移为 $f[i][j]=f[i][j-k]+f[i-1][ min(sw[i-1],k*2+p) ]$,此时 $sw[i]$ 表示第 $b<=2^i$ 时物品的体积和上取整为 $2^{sw[i]}$

注意上面枚举 $j$ 的时候要从大到小枚举

转移的细节挺多的...,最终答案即为 $f[m][1]$, $m$ 表示 $W$ 的最高位

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
using namespace std;
typedef long long ll;
inline int read()
{
int x=,f=; char ch=getchar();
while(ch<''||ch>'') { if(ch=='-') f=-; ch=getchar(); }
while(ch>=''&&ch<='') { x=(x<<)+(x<<)+(ch^); ch=getchar(); }
return x*f;
}
const int N=,M=;
int n,W,m,sw[];
struct Orb{
int val,w;
};
vector <Orb> V[];
ll f[][M];
int main()
{
while()
{
n=read(),W=read(); int w,v;
if(n==-&&W==-) break;
for(int i=;i<=;i++) V[i].clear(),sw[i]=;
memset(f,,sizeof(f));
for(int i=;i<=n;i++)
{
w=read(),v=read(); int cnt=;
while(!(w&)) w>>=,cnt++;
V[cnt].push_back((Orb){v,w}); sw[cnt]+=w;
}
int t=,cnt=; while(t<=W) t<<=,cnt++;
m=cnt-;
for(int i=;i<=m;i++)
{
int len=V[i].size();
for(int j=;j<len;j++)
for(int k=sw[i];k>=V[i][j].w;k--)
f[i][k]=max(f[i][k],f[i][k-V[i][j].w]+V[i][j].val);
}
// f[i][j]=f[i][j-k]+f[i-1][ (k<<1) | ( (W>>(i-1)) &1) ]
for(int i=;i<=m;i++)
{
sw[i]+=(sw[i-]+)>>; int p=(W>>(i-))&;
for(int j=sw[i];j>=;j--)
for(int k=;k<=j;k++)
f[i][j]=max(f[i][j],f[i][j-k]+ f[i-][min(sw[i-],(k<<)|p)] );
}
printf("%lld\n",f[m][]);
}
return ;
}

P3188 [HNOI2007]梦幻岛宝珠的更多相关文章

  1. 【洛谷】P3188 [HNOI2007]梦幻岛宝珠

    题目描述 给你N颗宝石,每颗宝石都有重量和价值.要你从这些宝石中选取一些宝石,保证总重量不超过W,且总价值最大为,并输出最大的总价值.  数据范围:N<=100;W<=2^30,并且保证每 ...

  2. [BZOJ 1190][HNOI2007]梦幻岛宝珠

    1190: [HNOI2007]梦幻岛宝珠 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1057  Solved: 611[Submit][Stat ...

  3. 【BZOJ1190】[HNOI2007]梦幻岛宝珠 分层背包DP

    [BZOJ1190][HNOI2007]梦幻岛宝珠 Description 给你N颗宝石,每颗宝石都有重量和价值.要你从这些宝石中选取一些宝石,保证总重量不超过W,且总价值最大为,并输出最大的总价值. ...

  4. BZOJ 1190 [HNOI2007]梦幻岛宝珠(背包)

    1190: [HNOI2007]梦幻岛宝珠 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1385  Solved: 798[Submit][Stat ...

  5. luogu 3188 [HNOI2007]梦幻岛宝珠

    LINK:梦幻岛宝珠 时隔多日 我再次挑战这道题.还是以失败告终. 我觉得这一道背包真的有点难度 这是一个数量较少 但是价值和体积较大的背包. 通常的01背包 要不就是体积小 要么是价值小 但这道题给 ...

  6. 【题解】 bzoj1190: [HNOI2007]梦幻岛宝珠 (动态规划)

    bzoj1190,懒得复制,戳我戳我 Solution: 这道题其实是一个背包(分组背包),但是由于数字比较大,就要重新构造dp式子.啃了三天才懂. \(dp[i][j]\)表示背包容积为\(j*2^ ...

  7. 1190: [HNOI2007]梦幻岛宝珠 - BZOJ

    Description 给你N颗宝石,每颗宝石都有重量和价值.要你从这些宝石中选取一些宝石,保证总重量不超过W,且总价值最大为,并输出最大的总价值. 数据范围:N<=100;W<=2^30 ...

  8. [HNOI2007]梦幻岛宝珠(背包)

    给你N颗宝石,每颗宝石都有重量和价值.要你从这些宝石中选取一些宝石,保证总重量不超过W,且总价值最大为,并输出最大的总价值.数据范围:N<=100;W<=2^30,并且保证每颗宝石的重量符 ...

  9. [HNOI2007]梦幻岛宝珠

    题解: 一道比较好的题目 首先比较显然的就是我们要按照a*2^b的b的顺序来枚举 那么状态f[i][j]表示当前在b,用了a*2^b 刚开始没想到怎么不同层之间搞 看了题解发现非常简单 由于每一层到最 ...

随机推荐

  1. 【NOIP2016提高A组8.11】种树

    题目 分析 题目要求把图删点,删成树. 考虑一下树的定义,点数n=边数m+1 并且,树中点两两之间联通,那么选的点就不能是割点. 可以用tarjan将图中最大的联通块,保证其中点两两之间有不止一条路径 ...

  2. HBase设计规范(转载)

    在这里讲什么设计规范实在是有些不知天高地厚,毕竟笔者本人也只是一个大数据技术的初学者,断然不敢制订什么设计规范的,所以请原谅我的狂妄,这个设计规范,只是本人对自己制订的,与别人无关. 之前,HBase ...

  3. 【leetcode】K-th Symbol in Grammar

    题目如下: 解题思路:直接把每行的数据计算出来肯定是不行的,因为N最大是30,那个第N行长度就是2^30次方,这显然不可取.那么就只能找规律了,我采取的是倒推法.例如假如我们要求出第四行第七个元素的值 ...

  4. ubuntu16.04 下 C# mono开发环境搭建

    本文转自:https://www.cnblogs.com/2186009311CFF/p/9204031.html 前记 之前我一直不看好C#的前景,因为我认为它只能在windows下运行,不兼容,对 ...

  5. spring 知识结构

  6. 简记特定容器list和forward_list算法

    链表类型list和forward_list有独有的sort.merge.remove.reverse和unique,而通用版本的是不能用于这两个类型的,因为所要求的迭代器不同,通用版本需要迭代器支持更 ...

  7. Pandas中的qcut和cut

    qcut与cut的主要区别: qcut:传入参数,要将数据分成多少组,即组的个数,具体的组距是由代码计算 cut:传入参数,是分组依据.具体见示例 1.qcut方法,参考链接:http://panda ...

  8. 电脑新安装JDK版本并运行使用该JDK版本问题

    情景:电脑上已正常安装一个jdk版本,如:1.7.0_71,因考虑到一些情况,现需要使用版本为1.7.0_80(1.8),故需新安装JDK,并使服务可以运行使用新安装的JDK版本. 网络找寻方法: ( ...

  9. Java 静态初始化块等的执行顺序

    实例代码 package text; class Root { static{ System.out.println("Root的静态初始化块"); } { System.out. ...

  10. Linux下" >/dev/null 2>&1 "详解

    在学习Linux的过程中,常会看到一些终端命令或者程序中有">/dev/null 2>&1 "出现,由于已经遇到了好几次了,为了理解清楚,不妨花点时间百度或者g ...