【学习笔记】多重背包相关优化——二进制优化/单调队列优化

多重背包——二进制优化/单调队列优化

  • 二进制优化
  • 单调队列优化

代码都是 POJ1742 的,注意,那道题二进制优化会超时。

普通的多重背包式子,物品个数限制:c[i]c[i]c[i],单个物品价值 w[i]w[i]w[i],每个物品的体积 v[i]v[i]v[i]

第一维是前 iii 个物品,第二维是背包容量。
dp[i,j]=max⁡(dp[i][j],dp[i−1][j−k∗v[i]]+k∗w[i])0≤k≤c[i]dp[i,j]=\max(dp[i][j],dp[i-1][j-k*v[i]]+k*w[i])\quad 0\le k\le c[i] dp[i,j]=max(dp[i][j],dp[i1][jkv[i]]+kw[i])0kc[i]

二进制优化

因为每个数都可以被表示成二进制形式。

二进制优化就是将物品的个数 c[i]c[i]c[i] 拆分成二进制形式,将多个物品捆绑成 2i2^i2i 个形式。

然后通过捆绑后的多重组合,能够组合出原来 0∼c[i]0\sim c[i]0c[i] 的所有选择。

i.e. 物品个数为 121212,就拆分成 1(20)+2(21)+4(22)+51(2^0)+2(2^1)+4(2^2)+51(20)+2(21)+4(22)+5,因为剩下的不足捆绑,就单独拎出来处理。

会发现这四个数就能组合出选择 0∼120\sim 12012 个物品的情况。

这就将第三维度枚举放的物品个数从 O(c[i])O(c[i])O(c[i]) 降到了 O(log⁡c[i])O(\log c[i])O(logc[i])

如果将所有信息看成同阶,则复杂度为 O(n2log⁡n)O(n^2\log n)O(n2logn)

#include <cstdio>
#include <cstring>
#define maxn 105
#define maxm 100005
int f[maxm], a[maxn], c[maxn];
int n, m;int main() {while( scanf( "%d %d", &n, &m ) ) {if( ! n and ! m ) break;for( int i = 1;i <= n;i ++ ) scanf( "%d", &a[i] );for( int i = 1;i <= n;i ++ ) scanf( "%d", &c[i] );memset( f, 0, sizeof( f ) );f[0] = 1;for( int i = 1;i <= n;i ++ ) {int k = 1;while( c[i] >= k ) {c[i] -= k;for( int j = m;j >= a[i] * k;j -- )f[j] |= f[j - a[i] * k];k <<= 1;}if( c[i] ) {for( int j = m;j >= a[i] * c[i];j -- )f[j] |= f[j - a[i] * c[i]];}}int ans = 0;for( int i = 1;i <= m;i ++ ) ans += f[i];printf( "%d\n", ans );}return 0;
}

单调队列优化

因为某种物品尽管有很多个,但是体积是一样的。

每次都会占用背包的 v[i]v[i]v[i] 体积。

所以如果原来背包的容量为 jjj,那么只会转移给 j+v[i],j+v[i]∗2,...,j+v[i]∗c[i]j+v[i],j+v[i]*2,...,j+v[i]*c[i]j+v[i],j+v[i]2,...,j+v[i]c[i],这些容量在 %v[i]\% v[i]%v[i] 下同余。

将背包容量 jjj,按照 %v[i]\% v[i]%v[i] 的余数分类考虑,显然两个不同的余数是不会相互转移的。

式子化地,令 a=j/v[i],b=j%v[i]⇒j=a∗v[i]+ba=j/v[i],b=j\%v[i]\Rightarrow j=a*v[i]+ba=j/v[i],b=j%v[i]j=av[i]+b

f[i][j]=max⁡{f[i−1][j−k∗v[i]]+k∗w[i]}⇒f[i][j]=max⁡{f[i−1][(a−k)∗v[i]+b]+k∗w[i]}f[i][j] = \max\Big\{f[i-1][j-k*v[i]]+k*w[i]\Big\}\Rightarrow f[i][j]=\max\Big\{f[i-1][(a-k)*v[i]+b]+k*w[i]\Big\}f[i][j]=max{f[i1][jkv[i]]+kw[i]}f[i][j]=max{f[i1][(ak)v[i]+b]+kw[i]}

k(0≤k≤c[i])k\ (0\le k\le c[i])k (0kc[i]) 反正都是枚举的变量,不妨令 k=a−kk=a-kk=ak

f[i][j]=max⁡{f[i−1][k∗v[i]+b]+(a−k)∗w[i]}f[i][j]=\max\Big\{f[i-1][k*v[i]+b]+(a-k)*w[i]\Big\}f[i][j]=max{f[i1][kv[i]+b]+(ak)w[i]}

整理得,f[i][j]=max⁡{f[i−1][k∗v[i]+b]−k∗w[i]}+a∗w[i](a−c[i]≤k≤a)f[i][j]=\max\Big\{f[i-1][k*v[i]+b]-k*w[i]\Big\}+a*w[i]\quad (a-c[i]\le k\le a)f[i][j]=max{f[i1][kv[i]+b]kw[i]}+aw[i](ac[i]ka)

换种形式表达 kkk 的范围:j/v[i]−c[i]]≤k≤j/v[i]j/v[i]-c[i]]\le k\le j/v[i]j/v[i]c[i]]kj/v[i]

是关于 jjj 的不减函数,一段区间,所以可以用单调队列优化。

时间复杂度是 O(nV)O(nV)O(nV),就没有 logloglog 了。

#include <cstdio>
#include <cstring>
#define maxn 100005
int n, m, head, tail;
int f[maxn], a[maxn], c[maxn], q[maxn];int main() {while( ~ scanf( "%d %d", &n, &m ) ) {if( ! n and ! m ) break;for( int i = 1;i <= n;i ++ ) scanf( "%d", &a[i] );for( int i = 1;i <= n;i ++ ) scanf( "%d", &c[i] );memset( f, 0, sizeof( f ) ); f[0] = 1;for( int i = 1;i <= n;i ++ ) {if( c[i] == 1 ) {for( int j = m;j >= a[i];j -- ) f[j] |= f[j - a[i]];continue;}if( a[i] * c[i] >= m ) {for( int j = a[i];j <= m;j ++ ) f[j] |= f[j - a[i]];continue;}for( int j = 0;j < a[i];j ++ ) {head = 1, tail = 0;for( int k = j;k <= m;k += a[i] ) {while( head <= tail and q[head] < k - a[i] * c[i] ) head ++;if( ! f[k] ) f[k] |= ( head <= tail );else q[++ tail] = k;}}}int ans = 0;for( int i = 1;i <= m;i ++ ) ans += f[i];printf( "%d\n", ans );}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/316732.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Game of Swapping Numbers

Game of Swapping Numbers 题意&#xff1a; A&#xff0c;B两个数组&#xff0c;让你对A进行k次操作&#xff0c;每次操作为选两个位置的数&#xff0c;进行交换&#xff0c;求最大化的Σ|Ai-Bi| 题解&#xff1a; 以前有做过最小化的情况&#xff0c;就是把每次交换作定量…

软件工程真的是一门什么用都没有的学科么?

软件工程真的是一门什么用都没有的学科么&#xff1f;-----读《构建之法》有感楔子我很惭愧&#xff0c;构建之法这本书已经出版四五年了&#xff0c;我之前却未曾涉猎&#xff0c;还是在通过组织长沙.net技术社区之后&#xff0c;才因为因缘际遇有幸认识邹欣邹老师之后&#x…

Ball Dropping

Ball Dropping 题意&#xff1a; 求&#xff1f;的具体长度 题解&#xff1a; 算一算就出来了 代码&#xff1a; #include<bits/stdc.h> using namespace std; int main(){double r,a,b,h;cin>>r>>a>>b>>h;if(2*r<b&&2*r<…

[WF2011] MachineWorks(李超树优化dp)

[WF2011]MachineWorksproblem BZOJ3963 solution 来得比较快的是&#xff0c;直接设 dpi,j:dp_{i,j}:dpi,j​: 考虑第 jjj 天换购 iii 机器。 但是马上注意到天数是 1e91e91e9 级别的&#xff0c;而机器是 1e51e51e5 级别。 稍微想想&#xff0c;就能知道&#xff0c;因为…

P3644 [APIO2015]八邻旁之桥(中位数、堆)

前言 卡了很长时间的一个题。 一开始 k1 的关键性质把握就跑偏了&#xff0c;后面基本在硬做… 关键就是一直把每个人当成一条线段作为整体在看&#xff0c;使问题很复杂… 最后用 three-pointers 磕磕绊绊搞出来了。 但是根本不用&#xff01; 解析 这题关键就在于&#xf…

尝试:Script Lab,开发模式之知识储备//SL02

前期00&#xff1a;深度&#xff1a;从 Office 365 新图标来看微软背后的设计新理念前期01&#xff1a;尝试&#xff1a;Script Lab&#xff0c;快速 Office 365 开发工具 //SL01本期02&#xff1a;尝试&#xff1a;Script Lab&#xff0c;开发模式之知识储备 //SL02项目特点适…

【学习笔记】Miller-Rabin(米勒-拉宾)素性测试,附常用表

TOC 素性测试是检验一个给定的整数是否为素数的测试。 最简单的就是用 n\sqrt{n}n​ 以内的数去试除。这是确定性的算法&#xff0c;即能准确知道 nnn 是否为质数。 但今天学习的是一种随机算法。 Fermat 小定理 如果 ppp 是一个质数&#xff0c;且 a%p≠0a\%p≠0a%p​0…

Hash Function

Hash Function 文章目录题意&#xff1a;题解&#xff1a;代码NTT代码FFT代码题意&#xff1a; 给定n个互不相同的数&#xff0c;找一个最小的模域&#xff0c;使得它们在这个模域下互不相同。n<5e5 题解&#xff1a; 考虑两个数a和b&#xff0c;a与b模m余数相同&#xf…

P5321 [BJOI2019]送别(LCT)

Foreword\text{Foreword}Foreword 肝了一下午一晚上的码农题… &#xff08;主要就是在 debug&#xff0c;LCT 太难 de 了…&#xff09; 感谢 M_sea&#xff0c;在调无可调认为LCT会不会不可做时&#xff0c;我看到了他的题解&#xff0c;几乎一样的思路&#xff0c;给了我继…

WebApi网关之Bumblebee和Ocelot性能对比

Bumblebee是基于.net core 2.1开发的WebApi网关组件&#xff0c;由于Bumblebee所追求的轻量化和性能&#xff0c;所以它并没有像Ocelot那样从asp.net core上进行扩展&#xff1b;而是构建在BeetleX.FastHttpApi之上&#xff0c;主要原因BeetleX.FastHttpApi有着更轻量化和高性能…

【无码专区11】异或2(结论 / 推式子 + 哈希hash + 大整数高精度 加减乘除重载考察)

本题已自我实现。但仍归于无码专区 problem 求 ∑i1n−1i⨁(n−i)\sum_{i1}^{n-1}i\bigoplus (n-i)∑i1n−1​i⨁(n−i)。 20%,n≤1e6;;50%,n≤1e9;;70%,n≤1e18;;100%,n≤1050020\%,n\le 1e6;;50\%,n\le 1e9;;70\%,n\le 1e18;;100\%,n\le 10^{500}20%,n≤1e6;;50%,n≤1e9;;7…

模板:常系数齐次线性递推(线性代数、多项式)

所谓常系数齐次线性递推&#xff0c;就是系数为常数的齐次线性递推。 &#xff08;逃&#xff09; 前言 sto Asta orz&#xff01; 又是一个名字高大上&#xff0c;实则小清新的算法&#xff01; 解析 考虑一个 k 次的线性递推&#xff1a; an∑i1kfian−ia_n\sum_{i1}^kf_…

2021牛客暑期多校训练营1

2021牛客暑期多校训练营1 题号题目知识点难度AAlice and Bob博弈论BBall Dropping计算几何签到CCut the TreeDDetermine the Photo Position签到EEscape along Water PipeFFind 3-friendly Integers真签到GGame of Swapping Numbers思维题&#xff0c;推导HHash FunctionFFT&a…

【无码专区12】子集和(背包dp)

此题已自我实现&#xff0c;但仍归于无码专区 本题在考场上就过了&#xff0c;所以难度并不高&#xff0c;发现性质即可。 problem 有 nnn 个正整数 a1,a2,...,ana_1,a_2,...,a_na1​,a2​,...,an​&#xff0c;他们的和为 mmm。你想对于其每一个子集 SSS&#xff0c;求出他…

Penguins

Penguins 题意&#xff1a; 有两个20*20的地图&#xff0c;有障碍物&#xff0c;两个地图各有一个小人&#xff0c;左侧地图的小人要从右下角走到右上角&#xff0c;右侧地图的小人要从左下角走到左上角&#xff0c;这两个小人是镜像移动的&#xff0c; 左侧小人右侧小人左移…

盲盒(随机概率 + 最大公约数)

盲盒problemsolutioncodeproblem 有 2n2n2n 个盲盒&#xff0c;每个盲盒有一个惊喜值 aia_iai​。 打开恰好 nnn 个盲盒&#xff0c;获得的惊喜值为这些盲盒惊喜值的最大公约数。 求能获得的最大惊喜值。 n≤1e5,ai≤1e12n\le 1e5,a_i\le 1e12n≤1e5,ai​≤1e12。 solution…

P5354 [Ynoi2017] 由乃的 OJ(树剖、位运算)

前言 当暴力思路与题解中的“暴力”不同时&#xff0c;继续想优化往往就渐行渐远了… 所以当没有头绪时&#xff0c;要勇于跳出原有的转化&#xff01; 这种位运算类型的优化似乎始终不在我的寄存器中…需要加强&#xff01; 解析 不难想到按位考虑的 O(nklog⁡2n)O(nk\log…

在 .NET Core 中运行 JavaScript

一.前言在 .NET Framework 时&#xff0c;我们可以通过V8.NET等组件来运行 JavaScript&#xff0c;不过目前我看了好几个开源组件包括V8.NET都还不支持 .NET Core &#xff0c;我们如何在 .NET Core 中运行 JavaScript 呢&#xff0c;答案是使用 NodeServices。关于为何有在 .N…

I love exam HDU - 6968

I love exam HDU - 6968 题意&#xff1a; 有n个考试科目&#xff0c;现在有m套复习资料&#xff0c;每套复习资料需要花费wi天使用&#xff0c;用完提升ci的分数&#xff0c;现在还有t天复习时间&#xff0c;挂科数目不能超过p&#xff0c;问所有达到的最大分数 题解&#…

[CF1442 D] Sum(分治优化dp + 结论)

CF1442D Sumproblemsolutioncodeproblem luogu翻译 solution 部分分做法&#xff0c;预处理每组前缀和&#xff0c;暴力背包 dpdpdp 转移&#xff1a;dpi,jmax⁡{dpi−1,j−ksumi(k)∣0≤k≤l[i]}dp_{i,j}\max\Big\{dp_{i-1,j-k}sum_i(k)\ \Big|\ 0\le k\le l[i]\Big\}dpi,j…