poj 1742 Coins(二进制拆分+bitset优化多重背包)
$ Coins $

$ solution: $
这道题很短,开门见山,很明显的告诉了读者这是一道多重背包。但是这道题的数据范围很不友好,它不允许我们直接将这一题当做01背包去做。于是我们得想一想优化。
** $ bitset $ 优化:** 这个是我最先想到的,因为这道题只牵扯到了能不能买,就是一个“是”和“否”的问题,也就是说这个背包并没有什么权值(只有“可以”和“不可以”)然后就是单纯的状态转移。而这不是我们的二进制最擅长的东西吗?(我们利用某一个硬币的面额进行更新时,直接用二进制的左右移和或运算即可)不过这一题的范围有一点大,所以我们选择 $ bitset $
二进制拆分优化: 这个还是得学的,不过他确实很奇妙,就像我们可以用2的一些乘方来表达出所有的数一样,我们可以将这个思想带到多重背包里来。但是我们的二进制能表达出所有的数,而我并不一定需要它表示出那么多的数啊(比如 $ 20,21\dots 27,28 $ 可以表示出256以内所有的数,但我只要23以内怎么办? )!而解决这个问题就是二进制拆分最难思考的地方了。
二进制拆分的重点,博主决定举个例子,能理解这个例子很多问题就能迎刃而解了:我现在有一个集合 $ {20,21\dots 27,28 } $ 我可以用它表示出256以内的任何数,而如果我只想要它表示出189以内的数,那我只需要将集合里最大的数改为 $ 189-2^7 $ 即可也就是 $ {20,21\dots 27,189-27 } $ 可以表示出189以内的任何数。这里的证明留给大家,因为博主自己学习的时候发现如果单纯看证明理解似乎不如手算去感性理解。然后说明一下这个方法其实有一个地方需要注意(也是迷惑人最多的地方):博主为什么选择了从 $ 2^0\dots 2^7 $ 为什么又选了189这个数字,其实是因为必须满足向 $ 2^p $ 这个集合中最大的数一定是要比189这样的常数 $ k $ 小的最大的2的乘方!
$ code: $
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#define ll long long
#define db double
#define inf 0x7fffffff
#define rg register int
using namespace std;
bitset<100005> f;
int n,m,ans;
int a[105];
inline int qr(){
register char ch; register bool sign=0; rg res=0;
while(!isdigit(ch=getchar())) if(ch=='-')sign=1;
while(isdigit(ch)) res=res*10+(ch^48),ch=getchar();
return sign?-res:res;
}
int main(){
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
while((n=qr())&&(m=qr())){
f&=1; f[0]=1; ans=0;
for(rg i=1;i<=n;++i) a[i]=qr();
for(rg i=1;i<=n;++i){ rg x=qr();
for(rg j=1;j<=x;x-=j,j<<=1)
if(a[i]*j<=m)f|=f<<(a[i]*j);
if(x*a[i]<=m)f|=f<<(x*a[i]);
}for(rg i=1;i<=m;++i) if(f[i])++ans;
printf("%d\n",ans);
}
return 0;
}
poj 1742 Coins(二进制拆分+bitset优化多重背包)的更多相关文章
- 【题解】Coins(二进制拆分+bitset)
[题解]Coins(二进制拆分+bitset) [vj] 俗话说得好,bitset大法吼啊 这道题要不是他多组数据卡死了我复杂度算出来等于九千多万的选手我还不会想这种好办法233 考虑转移的实质是怎样 ...
- poj 1742 Coins(二进制优化多重背包)
传送门 解题思路 多重背包,二进制优化.就是把每个物品拆分成一堆连续的\(2\)的幂加起来的形式,然后把最后剩下的也当成一个元素.直接类似\(0/1\)背包的跑就行了,时间复杂度\(O(nmlogc) ...
- POJ - 1276 二进制优化多重背包为01背包
题意:直接说数据,735是目标值,然后3是后面有三种钱币,四张125的,六张五块的和三张350的. 思路:能够轻易的看出这是一个多重背包问题,735是背包的容量,那些钱币是物品,而且有一定的数量,是多 ...
- hdu 2844 poj 1742 Coins
hdu 2844 poj 1742 Coins 题目相同,但是时限不同,原本上面的多重背包我初始化为0,f[0] = 1;用位或进行优化,f[i]=1表示可以兑成i,0表示不能. 在poj上运行时间正 ...
- [Bzoj 1192][HNOI2006]鬼谷子的钱袋(二进制优化多重背包)
(人生第一篇bzoj题解有点激动 首先介绍一下题目: 看它题目那么长,其实意思就是给定一个数a,求将其拆分成n个数,通过这n个数可以表示出1~a中所有数的方案中,求最小的n. 您看懂了嘛?不懂咱来举个 ...
- poj1014二进制优化多重背包
Dividing Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 53029 Accepted: 13506 Descri ...
- BZOJ 1531 二进制优化多重背包
思路: 讲道理我应该写单调队列优化多重背包的 但是我不会啊 但是我现在! 还不会啊 我就写了个二进制优化的.. 过了 //By SiriusRen #include <cstdio> #i ...
- 51nod 1086 背包问题 V2(二进制优化多重背包)
题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1086 题解:怎么用二进制优化多重背包,举一个例子就明白了. ...
- [tyvj-1194]划分大理石 二进制优化多重背包
突然发现这个自己还不会... 其实也不难,就和快速幂感觉很像,把物品数量二进制拆分一下,01背包即可 我是咸鱼 #include <cstdio> #include <cstring ...
随机推荐
- POJ——2251Dungeon Master(三维BFS)
Dungeon Master Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 25379 Accepted: 9856 D ...
- [BZOJ4776] [Usaco2017 Open]Modern Art(差分 + 思维?)
传送门 可以预处理出每种颜色的上下左右的位置,这样就框出来了一个个矩形,代表每种颜色分别涂了哪里. 然后用二维的差分. 就可以求出来每个位置至少涂了几次,如果 > 1 的话,就肯定不是先涂的, ...
- BZOJ4446 [Scoi2015]小凸玩密室 【树形Dp】
题目 小凸和小方相约玩密室逃脱,这个密室是一棵有n个节点的完全二叉树,每个节点有一个灯泡.点亮所有灯 泡即可逃出密室.每个灯泡有个权值Ai,每条边也有个权值bi.点亮第1个灯泡不需要花费,之后每点亮4 ...
- XPosed框架_简单的应用
0. Xposed框架简介 关于Xposed框架相信大家应该不陌生了,他是Android中Hook技术的一个著名的框架,而Xposed框架是免费的而且还是开源的,本文主要介绍如何通过这个框架来进行系统 ...
- MySql将查询结果插入到另外一张表
今天遇到一个业务需求是这样的:对在职员工超过55岁提醒.我想的思路是查询员工表,然后将超过55岁的人的信息存到另一个表,并且以消息的形式给用户提示,用户处理掉之后此消息失效(在数据库做标记). 不管是 ...
- Mybatis resultMap空值映射问题
参考博客:https://www.oschina.net/question/1032714_224673 http://stackoverflow.com/questions/22852383/how ...
- curl抓取数据
抓取数据的代码: $url='抓取数据的网站路径'; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); //参数为1表示传输数据,为0表示 ...
- dbms_metadata.get_ddl的使用总结
https://blog.csdn.net/newhappy2008/article/details/34823339
- (7)ASP.NET WEB服务器控件
1. <body> <form id="form1" runat="server"> <div> <asp:Label ...
- PC下ubuntu查找PC串口并加入用户组
1. 查看ttyS0隶属的组:ls -l /dev/ttyS0 //发现隶属于dialout组 输出: crw-rw---- 1 root dialout 4, 64 9月 9 08:23 /d ...