题目描述

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

输入格式

输入文件中包含多组数据。
  每组数据的格式如下:
  第一行是两个正整数n和W,1≤n≤100,1≤W≤2^30,分别表示宝石的数目和最多能带走的宝石重量。
  接下来的n行,每行有两个正整数weighti和valuei,1≤weighti≤2^30, 0≤valuei≤2^30,
  分别表示第i颗宝石的重量和价值,且保证weighti能写成a*2^b(1≤a≤10,0≤b≤30)的形式。
  同一行的两个正整数之间用空格隔开。
  最后一组数据的后面有两个-1,表示文件的结束。这两个-1并不代表一组数据,
  你不需对这组数据输出结果。并且输入文件中数据的组数不超过20。

输出格式

对于输入的每组数据,输出一个整数C,表示小P最多能带走的宝石的总价值。
  每个结果整数C单独占一行,且保证C不会超过2^30。

输入样例
  4 10
  8 9
  5 8
  4 6
  2 5
  4 13
  8 9
  5 8
  4 6
  2 5
  16 75594681
  393216 5533
  2 77
  32768 467
  29360128 407840
  112 68
  24576 372
  768 60
  33554432 466099
  16384 318
  33554432 466090
  2048 111
  24576 350
  9216 216
  12582912 174768
  16384 295
  1024 76
  -1 -1

输出样例
  14
  19
  1050650

分析

乍一看,怎么又是背包。

再一看,woc,范围怎么这么大。

有一看,好像可以根据2的几次幂来分层,最后合并。

仔细一想,还不是要很大的空间和复杂度,而且还不会写。

再一想,千年等一回

最后放弃去网上找题解,结果发现有一个贪心,从一位与下一位的合并时,只考虑这一位1000以内的情况。

用dp[i][j]表示背包的容量已经占用了j*2^i+(w&((1<< i)-1))时的最大价值

先对于每一个i进行背包的合并,然后再考虑把每一位合并。

合并时,dp[i][j]=max(dp[i][j],dp[i][j-k]+dp[i-1][2*k+((w>>(i-1) )&1)])

其中(2*k+((w>>(i-1))&1))可以通过倒推得到,用j*2^i+(w&((1<< i)-1))减去k*2^i+(w&((1<< i)-1))即可

upd 20191014

突然想到一种对dp转移式子的感性理解,第i位的k到第i-1位后就是k*2,而((w>>(i-1) )&1)就代表w在第i-1位是否有1

所以dp转移式子还可以优化成

dp[i][j]=max(dp[i][j],dp[i][j-k]+max(dp[i-1][2*k+((w>>(i-1) )&1)],dp[i-1][2*k]))

顺便把另一种写法也写了。。。。。。

推荐一个博客

好像物品可以一个一个加进去,时间上会有很大的优化,然而并不会写。

代码(不要在意那个O2)

#pragma GCC optimize (2)
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m,cnt,i,j,k,w,val,f[][];
int main()
{
while(scanf("%d%d",&n,&m))
{
if(n==-&&m==-)return ;
memset(f,,sizeof f);
for(i=;i<=n;i++)
{
scanf("%d%d",&w,&val);
cnt=;while(w%==)w/=,cnt++;
for(j=;j>=w;j--)f[cnt][j]=max(f[cnt][j],f[cnt][j-w]+val);
}
int lim=;
for(i=m;i;i/=)lim++;lim--;
for(i=;i<=lim;i++)for(j=min(, m>>i);j>=;j--)for(k=;k<=j;k++)
f[i][j]=max(f[i][j],f[i][j-k]+f[i-][min(,(k*)|((m>>(i-))&))]);
printf("%d\n",f[lim][]);
}
}
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
long long f[][];
int n,m,st[][][];
int main()
{
while(scanf("%d%d",&n,&m))
{
if(n==-&&m==-)return ;
memset(f,,sizeof f);memset(st,,sizeof st);
for(int i=,a,b,cnt;i<=n;i++)
{
scanf("%d%d",&a,&b);cnt=;
while(a%==)a/=,cnt++;
st[cnt][++st[cnt][][]][]=a;st[cnt][st[cnt][][]][]=b;
}
int lim=;for(int i=m/;i;i/=)lim++;
for(int i=;i<=lim;i++)
{
if(i)for(int j=;j<=;j++)f[i][j]=f[i-][min(,(j<<)|((m>>(i-))&))];
for(int j=;j<=st[i][][];j++)for(int k=min(m>>i,);k>=st[i][j][];k--)
f[i][k]=max(f[i][k],f[i][k-st[i][j][]]+st[i][j][]);
}
printf("%lld\n",f[lim][]);
}
}

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

  1. P3188 [HNOI2007]梦幻岛宝珠

    传送门 注意到 $a,b$ 不大 考虑对每一个 $a*2^b$ 的 $b$ 分别背包 设 $f[i][j]$ 表示只考虑 $b=i$ 的物品时,容量为 $j= \sum a$ 的最大价值 这个就是普通 ...

  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. 洛谷 P3190 [HNOI2007]神奇游乐园 解题报告

    P3190 [HNOI2007]神奇游乐园 Description 给你一个 \(m * n\) 的矩阵,每个矩阵内有个权值\(V(i,j)\) (可能为负数),要求找一条回路,使得每个点最多经过一次 ...

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

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

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

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

随机推荐

  1. 爬虫之PyQuery的base了解

    爬虫之PyQuery的base了解 pyquery库是jQuery的Python实现,能够以jQuery的语法来操作解析 HTML 文档,易用性和解析速度都很好,和它差不多的还有BeautifulSo ...

  2. 用js写的简单的下拉菜单

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  3. hadoop完整集群遇到问题汇总

    1> 设置静态ip: 由于虚拟机在重启之后ip会再次重置,为了后续的麻烦我吗可以设置成静态ip的方式: cd   /etc/sysconfig/network-scripts/ 修改对比如下: ...

  4. Springboot默认定时任务——Scheduled注解

    1.pom配置 <dependencies> <dependency> <groupId>org.springframework.boot</groupId& ...

  5. 【转】如何使用jupyter编写数学公式(译)

    [1.如何使用jupyter编写数学公式(译)][1] [1]: https://www.jianshu.com/p/93ccc63e5a1b

  6. flask-sqlalchemy用法详解

    一. 安装 $ pip install flask-sqlalchemy 二. 配置 配置选项列表 : 选项 说明 SQLALCHEMY_DATABASE_URI 用于连接的数据库 URI .例如:s ...

  7. altium designer(AD13)隐藏敷铜的方法

    覆铜,就是将PCB上闲置的空间作为基准面,然后用固体铜填充,这些铜区又称为灌铜.敷铜的意义在于,减小地线阻抗,提高抗干扰能力;降低压降,提高电源效率;还有,与地线相连,减小环路面积. 如果拿到别人的P ...

  8. mysql5.7切换导致gtid不一致

    今天在公司的工程环境中做了个案例,手动切换关闭主库的mysql服务,从库上升为主库之后,发现主库处于read_only状态,通过高可用的组件观察了剩余主从库的alive以及delay的状态发现均正常. ...

  9. MySQL 空事务

    问题描述;    研发同事反应MySQL数据库有锁,检查innodb_trx时,发现有很多长时间未结束的空事务.    这些事务的trx_mysql_thread_id都为0,因此不能通过kill   ...

  10. 安装k8s,单master脚本

    这个以一个普通xxx帐户运行即可. 因为上面root帐号作了sudoer的操作的. 还有,最好将xxx帐号加入docker组,这样xxx也可以执行docker命令了. 可以看到,这个脚本还需要其它目录 ...