【洛谷】P3188 [HNOI2007]梦幻岛宝珠
题目描述
给你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]梦幻岛宝珠的更多相关文章
- P3188 [HNOI2007]梦幻岛宝珠
传送门 注意到 $a,b$ 不大 考虑对每一个 $a*2^b$ 的 $b$ 分别背包 设 $f[i][j]$ 表示只考虑 $b=i$ 的物品时,容量为 $j= \sum a$ 的最大价值 这个就是普通 ...
- [BZOJ 1190][HNOI2007]梦幻岛宝珠
1190: [HNOI2007]梦幻岛宝珠 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 1057 Solved: 611[Submit][Stat ...
- 【BZOJ1190】[HNOI2007]梦幻岛宝珠 分层背包DP
[BZOJ1190][HNOI2007]梦幻岛宝珠 Description 给你N颗宝石,每颗宝石都有重量和价值.要你从这些宝石中选取一些宝石,保证总重量不超过W,且总价值最大为,并输出最大的总价值. ...
- BZOJ 1190 [HNOI2007]梦幻岛宝珠(背包)
1190: [HNOI2007]梦幻岛宝珠 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 1385 Solved: 798[Submit][Stat ...
- luogu 3188 [HNOI2007]梦幻岛宝珠
LINK:梦幻岛宝珠 时隔多日 我再次挑战这道题.还是以失败告终. 我觉得这一道背包真的有点难度 这是一个数量较少 但是价值和体积较大的背包. 通常的01背包 要不就是体积小 要么是价值小 但这道题给 ...
- 【题解】 bzoj1190: [HNOI2007]梦幻岛宝珠 (动态规划)
bzoj1190,懒得复制,戳我戳我 Solution: 这道题其实是一个背包(分组背包),但是由于数字比较大,就要重新构造dp式子.啃了三天才懂. \(dp[i][j]\)表示背包容积为\(j*2^ ...
- 洛谷 P3190 [HNOI2007]神奇游乐园 解题报告
P3190 [HNOI2007]神奇游乐园 Description 给你一个 \(m * n\) 的矩阵,每个矩阵内有个权值\(V(i,j)\) (可能为负数),要求找一条回路,使得每个点最多经过一次 ...
- 1190: [HNOI2007]梦幻岛宝珠 - BZOJ
Description 给你N颗宝石,每颗宝石都有重量和价值.要你从这些宝石中选取一些宝石,保证总重量不超过W,且总价值最大为,并输出最大的总价值. 数据范围:N<=100;W<=2^30 ...
- [HNOI2007]梦幻岛宝珠(背包)
给你N颗宝石,每颗宝石都有重量和价值.要你从这些宝石中选取一些宝石,保证总重量不超过W,且总价值最大为,并输出最大的总价值.数据范围:N<=100;W<=2^30,并且保证每颗宝石的重量符 ...
随机推荐
- 【洛谷 P3804】 【模板】后缀自动机
题目链接 #include <cstdio> #include <cstring> #include <algorithm> using namespace std ...
- ToLua Timer机制
从一个Bug说起: 在内部试玩时发现有个任务的玩家跟随Npc逻辑挂了. telnet连接到出问题的设备上, 开始搞事情 这个跟随的逻辑是一个Timer驱动的. 这个Timer在主角创建时就会启动. 一 ...
- 你再也不用使用 Redux、Mobx、Flux 等状态管理了
Unstated Next readme 的中文翻译 前言 这个库的作者希望使用 React 内置 API ,直接实现状态管理的功能.看完这个库的说明后,没有想到代码可以这个玩.短短几行代码,仅仅使用 ...
- requests爬虫get请求
1.简单get请求 url = 'https://www.baidu.com' headers = { 'accept': 'text/html,application/xhtml+xml,appli ...
- mysql学习之基础篇01
大概在一周前看了燕十八老师讲解的mysql数据库视频,也跟着学了一周,我就想把我这一周所学的知识跟大家分享一下:因为是第一次写博客,所以可能会写的很烂,请大家多多包涵.文章中有不对的地方还请大家指出来 ...
- mysql 5.7 my.cnf配置
此为配置上生产环境的参数,后续补充参数说明 [client] port=3306 socket = /data/mysql/tmp/mysql.sock # default-character-set ...
- Kotlin属性揭秘与延迟初始化特性
在上一次https://www.cnblogs.com/webor2006/p/11210181.html学习了Kotlin的伴生对象,这次来学习属性相关的东东. 属性揭秘: 先声明一个属性: 没啥可 ...
- [转] ubuntu16.04添加系统 service, 并设置开机自动启动
转:https://www.jianshu.com/p/1958878646bd 1. 创建pfly.service文件 2. 执行 systemctl daemon-reload 3. 执行 sy ...
- 使用Jackson的@JsonFormat注解时出现少了 8 个小时
比如数据库存的日期是2018-01-05,转成json则变成了2018-01-04 解决办法: @JsonFormat(pattern="yyyy-MM-dd") public D ...
- mysql跨表删除多条记录
Mysql可以在一个sql语句中同时删除多表记录,也可以根据多个表之间的关系来删除某一个表中的记录. 假定我们有两张表:Product表和ProductPrice表.前者存在Product的基本信息, ...