背包dp

[BJOI2019] 排兵布阵 (背包dp与贪心)

题目

小 C 正在玩一款排兵布阵的游戏。在游戏中有 \(n\) 座城堡,每局对战由两名玩家来争夺这些城堡。每名玩家有 \(m\) 名士兵,可以向第 \(i\) 座城堡派遣 \(a_i\) 名士兵去争夺这个城堡,使得总士兵数不超过 \(m\)

如果一名玩家向第 \(i\) 座城堡派遣的士兵数严格大于对手派遣士兵数的两倍,那么这名玩家就占领了这座城堡,获得 \(i\) 分。

现在小 C 即将和其他 \(s\) 名玩家两两对战,这 \(s\) 场对决的派遣士兵方案必须相同。小 C 通过某些途径得知了其他 \(s\) 名玩家即将使用的策略,他想知道他应该使用什么策略来最大化自己的总分。

由于答案可能不唯一,你只需要输出小 C 总分的最大值。

\(1\le s \le 100\)
\(1\le n \le 100\)
\(1\le m \le 20000\)
对于每名玩家 \(a_i \ge 0\)\(\sum\limits_{i=1}^n a_i \le m\)

题解

\(f[i][j]\) 表示第 \(i\) 个城堡时,已派出 \(j\) 个士兵。

贪心派出恰好严格大于某一玩家派出的数量的两倍。可以排序预处理出 \(g[i][k]\) 表示第 \(i\) 个城堡,出兵数量第 \(k\) 大的人出兵数量

转移方程即为:

\[f[j]=\max\lbrace f[j-g[i][k]*2-1]+k*i,f[j]\rbrace \]

2022牛客OI赛前集训营 Day5 T3 子集 (推式子+背包意义的转换)

题目

给定一个正整数 \(M\) ,对于集合 \(S\) 定义

\[F_0(S)=\left[\sum_{x\in S}=M\right] \]

同时有

\[F_k(S)=\sum_{T\subseteq S}F_{k-1}(T)~~~(k\ge 1) \]

给定集合 \(S=\lbrace a_1,a_2,\cdots,a_n\rbrace\) 和一个正整数 \(k\) ,求\(F_k(S)\)

\(n,M,a_i\le 5000\)

题解

一眼丁真,应该是个背包,但是这 \(k\) 次子集求和比较的麻烦

遇事不决就打表,我们发现了一个规律:

\[F_k(S)=\sum_{T\subseteq S}F_0(T)k^{n-|T|} \]

考虑归纳法证明这个东西

首先 \(k=1\) 的时候,显然成立

\(k\) 时成立,则 \(k+1\) 时有

\[\begin{aligned} F_{k+1}(S)=&\sum_{T\subseteq S}F_{k}\\=&\sum_{T\subseteq S}\sum_{C\subseteq T}F_0(C)\cdot k^{|T|-|C|}\\=&\sum_{C\subseteq S}F_0(C)\cdot \sum_{i=0}^{|S|-|C|}\binom{|S|-|C|}{i}k^i\\=&\sum_{C\subseteq S}F_0(C)\cdot (k+1)^{|S|-|C|} \end{aligned} \]

于是我们证明了我们的猜想,那么这个问题就变成了一个01背包的问题,设 \(f[i][j][x]\) 表示考虑到第 \(i\) 个数,一共选了 \(j\) 个数,这些数的和是 \(x\) 的方案数,最后对应的 \(j\) 乘上 \(k^{n-j}\) 即可,时间复杂度是 \(\mathcal O(n^2M)\) 的,无法通过本题

但事实上,仔细想一想我们dp的状态是有冗余的,所以我们考虑更改dp的定义,设 \(f[i][j]\) 表示考虑了前 \(i\) 个数,和为 \(j\) 时对答案的贡献,初始状态 \(f[0][0]=k^n\) 表示空集的贡献,转移时每增加一个物品就在原来的那个位置的基础上除一个 \(k\) ,除此之外这就是一个01背包,代码如下

f[0]=ksm(k,n);
for(int i=1;i<=n;++i)
	for(int j=M;j>=a[i];--j)
	{
		f[j]+=f[j-a[i]]*inv%mod;
		f[j]%=mod;
	}

我们相比原来去除掉了选取个数这一个冗余状态,最后这个东西的时间复杂度是 \(\mathcal O(nM)\)

P4141 消失之物 (对背包转移的理解)

题目

\(N\) ( \(N\le 2000\) ) 个物品,体积分别是 \(w_1, w_2 ,\cdots, w_N\)

对于每个 \(i\)\(x\) 求:不使用第 \(i\) 个物品能有多少种恰好装满体积为 \(x\) 的背包。

其中 \(x\)\(1\)\(M\) ( \(M \le 2000\) ) 之间

题解

暴力是 \(\mathcal O(n^2m)\)\(n\) 次背包

考虑少了某个物品怎么办

考虑在01背包DP时会用到的这个转移

for(int j=m;j>=w[i];--j)
    f[j]+=f[j-w[i]];

我们少了i物品就是在原来的基础上少了一次这样的转移,因此

memcpy(g,f,sizeof f);
for(int j=w[i];j<=m;++j)
    g[j]-=g[j-w[i]];

处理一下就行

有趣背包问题(交换值域与状态)

题目

初始有 \(m\) 块钱,\(n\) 个物品,其中第 \(i\) 个物品花费 \(\text{cost}[i]\) 块钱,价值为 \(\text{val}[i]\),我们现在想要知道我们用这些钱能买到最多多少价值的东西。

\(n\le 100,1\le \text{val}[i]\le 5,1\le \text{cost}[i],m\le 10^9\)

题解

一般的背包问题是设 \(f[i][j]\) 表示考虑到第 \(i\) 个物品,有 \(j\) 的花费所能取得的最大价值,但是此题的最大花费太大,无法放到状态中

所以我们考虑设 \(f[i][j]\) 表示考虑到第 \(i\) 个物品,产生 \(j\) 的价值所需要的最小花费,找 \(\text{cost} \le m\) 中最大的 \(j\) 即可。

P2340 [USACO03FALL]Cow Exhibition G (可行性转最优化)

题意

\(n\) 个物品,第 \(i\) 个物品有 \(a_i,b_i\) 两种花费,可以为负,价值为两者之和,要求在满足每项总花费大于 \(0\) 的情况下,最大化价值

\(n\le 400 |a_i|,|b_i|\le 1000\)

题解

一个朴素的想法是,设 \(f[i][a][b]\) 表示考虑到第 \(i\) 个物品,前者的总花费为 \(a\) ,后者的总花费是 \(b\) 的情况下,是否存在这样一种方案,但是这太sb,所以考虑可行性转最优化

\(f[i][a]\) 表示在考虑到第 \(i\) 个物,前者花费是 \(a\) 的情况下 \(b\) 的最大值,那么这就是一个朴素的01背包了,直接转移就行

P1941 [NOIP2014 提高组] 飞扬的小鸟 (背包建模)

题面

题解

\(f[i][j]\) 表示横坐标为 \(i\) 时高度为 \(j\) 的最少点击次数,转移方式如下:

  • 上升为完全背包
  • 下降为01背包
  • 越界就特判

时间复杂度 \(\mathcal{O}(n\times m)\)

P1064 [NOIP2006 提高组] 金明的预算方案 (依赖背包)

题面

题解

大力分讨即可

  1. 不选,然后去考虑下一个
  2. 选且只选这个主件
if(j>=v[nw]) f[j]=max(f[j],f[j-v[nw]]+val[nw]);
  1. 选这个主件,并且选附件1
if(j>=v[nw]+v[v1]) f[j]=max(f[j],f[j-v[nw]-v[v1]]+val[nw]+val[v1]);
  1. 选这个主件,并且选附件2
if(j>=v[nw]+v[v2]) f[j]=max(f[j],f[j-v[nw]-v[v2]]+val[nw]+val[v2]);
  1. 选这个主件,并且选附件1和附件2
if(j>=v[nw]+v[v1]+v[v2]) f[j]=max(f[j],f[j-v[nw]-v[v1]-v[v2]]+val[nw]+val[v1]+val[v2]); 

时间复杂度同01背包

BZOJ3163 [HEOI2013] 新背包问题(分治+背包)

题目

\(N\) 个物品,第 \(i\) 个物品有 \(c[i]\) 个,购买第 \(i\) 个物品需要 \(a[i]\) 元,可获利 \(b[i]\) 的价值。有 \(m\) 个询问,每次询问:如果第 \(x\) 个物品禁止购买,你有 \(y\) 元的话,能获得的最大价值是多少?询问之间互相独立。

\(N\le 1000,m\le 3\times 10^5\)

题解

初始 \(\text{solve}(1,n)\)

  • 递归的函数到 \(\text{solve}(l,r)\),维护的dp数组,记录的是除去 \([l,r]\) 外的物品的构成的背
    包数组。
  • \(\text{solve}(l,mid)\) 时,把 \([mid+1,r]\) 内的物品加入dp数组。

我们这里定义的加入这个物品 \(u\) ,就是多考虑上这个物品之后构成的dp数组,也就是直接按照多重背包的方式转移就好

\(l=r\) 时,将对应所有的询问在dp数组查询即可

单调队列优化时复杂度 \(\mathcal O(nw\log n)\) ,每个物品被加进去 \(\log\) 次,每次 \(\mathcal O(w)\)

可行性背包问题(bitset优化)

题目

给出 \(n\) 个物品,每个物品有体积 \(v[i]\) ,要求把物品分成两堆,然后使得两堆物品体积的差的绝对值最小。

\(n,v[i]\le 100\)

题解

我们设总体积为$ \text{sum} $,那么我们必定会存在一堆体积和是小于等于 \(\text{sum}/2\)的,然后就是要求去选出一些物品总体积小于等于 \(\text{sum}/2\) ,最大能取到的体积是多少。

这就是经典的背包问题了,同时可行性的背包问题可以 \(\text{bitset}\) 优化

P1272 重建道路 (树形背包)

题面

给你一颗 \(N\) 个点的树,要求从其中断开几条边,使得分离出一个大小为 \(P\) 的子树,要求最小化边数

题解

\(f[u][s]\) 表示以 \(u\) 为根的子树保留大小为 \(s\) 的子树所需要的最小花费

初始化:

\[f[i][0]=0,f[i][1]=\text{与}i\text{相邻的点数} \]

转移

\[f[u][s]=\min_{v\in\text{son}_u}\lbrace f[u][k]+f[v][s-k]-2\rbrace \]

注意我们的状态设计,连接 \(u,v\) 的边被消除了两次,所以要减 \(2\)

化学反应(二维背包dp)

题面

给出 \(n\) 个化学反应,每个反应消耗 \(a[i]\) 升氧气和 \(b[i]\) 升氢气,可以得到 \(w[i]\) 的价值,现在总共有 \(X\) 升氧气和 \(Y\) 升氢气,求我们最多可以得到多少价值

题解

\(f[i][x][y]\) 表示前 \(i\) 个物品,消耗了 \(x\) 的氧气和 \(y\) 的氢气所能得到的最大收益是多少。

然后考虑一个物品选还是不选即可

vijos1240 (根据题目性质给背包增维)

题目

  1. 给你一些房间,告诉你这些房间的容纳人数和价格。

  2. 安排一定数量的人住到旅馆里,满足:

    不同性别的人如果不是夫妻那么不能住一个房间。
    一对夫妻如果住在一起,那么房间不能安排其他的人进去哪怕房间
    没盛满人

  • 你来写一个程序帮助佳佳找到安排这些来参加旅行的人住进旅馆所需要
    的最小花费。
  • \(M\):参加旅行的男性人数、 \(f\):参加旅行的女性人数、 \(r\):旅馆的房间数、\(c\):这些男女中有多少对夫妻、\(B_i\):每个房子容纳人数和、\(P_i\):每个房子价格。注意每一个人不是单身就是和他/她唯一的妻子/丈夫一起参加旅行。
    \(0\le m,f,r\le 300,0\le c\le \min(m,f),0\le P_i\le 10 2\le B_i\le 300\)

题解

首先考虑一件事情:如果有两对及以上夫妻,那么拆开分别住一定不会比他们在一起更劣

因此,要么只有一对夫妻,要么没有

于是,设 \(f[i][j][k][0/1]\) 表示考虑到第 \(i\) 号房间,有 \(j\) 个男性和 \(k\) 个女性,是否存在一对夫妻时的最小花费

\[f[i,j,k,0]=\min\lbrace f[i-1,j,k,0],f[i-1,j-v[i],k,0]+p[i],f[i-1,j,k-v[i],0]+p[i]\rbrace \\ ◦f[i,j,k,1]=\min\lbrace f[i-1,j,k,1],f[i-1,j-v[i],k,1]+p[i],f[i-1,j,k-v[i],1]+p[i],f[i-1,j-1,k-1,0]+p[i]\rbrace \]

P3188 [HNOI2007]梦幻岛宝珠 (通过特殊条件缩小范围)

题面

给你 \(N\) 颗宝石,每颗宝石都有重量和价值 \(V\) 。要你从这些宝石中选取一些宝石,保证总重量不超过 \(W\) ,并输出最大的总价值,每
颗宝石的重量符合 \(a\times 2^b\)
\(V\le 1\times 10^9,a\le 10,b\le 30\)

题解

首先,这道题的数据范围及其的吓人,但是注意到 \(a\) 的范围很小,所以我们可以根据 \(b\) 做分层dp

\(f[i][j]\) 表示第 \(i\) 层的背包花费为 \(j\) 时的最大价值,直接01背包转移即可

难点在于如何合并每一层的背包,设 \(g[i][j]\) 表示考虑到前 \(i\) 层物品体积小于等于 \(j\times 2^i+W\And (1<<(i-1))\) 时的最大价值,转移如下

\[g[i][j]=\max_k\lbrace f[i][j-k]+g[i-1][2\times k+(W>>(i-1))\And 1]\rbrace \]

感性理解一下,这个过程就是高位把它的空间分给了低位,所以要乘 \(2\) ,与此同时,背包里本来就有供低位使用的空间,所以要加上

注意到 \(n\le 100,a\le 10\) ,所以重量最多就记到 \(1000\) 就行了,时间复杂度 \(\mathcal O(an^2)\)

LOJ6089 小Y的背包计数问题 (剩余系分类与处理不降序列的方法)

题目

小Y有一个大小为 \(n\) 的背包,并且小Y有 \(n\) 种物品。

对于第 \(i\) 种物品,共有 \(i\) 个可以使用,并且对于每一个 \(i\) 物品,体积均为 \(i\)

求小Y把该背包装满的方案数为多少

定义两种不同的方案为:当且仅当至少存在一种物品的使用数量不同。

\(n\le 1\times 10^5\)

题解

首先有个显而易见的性质:大小 \(\ge \sqrt n\) 的物品不可能被选完

因此我们的问题变成前 \(\sqrt n\) 个是多重背包,后面的都是完全背包

  • 对于前 \(\sqrt{n}\) 个数

我们可以直接多重背包做吗? \(\mathcal O(n\log n \sqrt n)\) 的复杂度是无法接受的,考虑优化转移

\[f[i][j]=\sum f[i-1][j-ki] \]

我们发现每次都是从 \(j\mod i\) 的剩余系中转移而来,因此依照剩余系分类,前缀和优化转移,时间复杂度降为 \(\mathcal O(n\sqrt{n})\)

  • 对于后面的数

首先,我们依次选择 \([\sqrt{n},n]\) 的物品,最终这些物品会形成一个单调不降的序列,那么我们有一种经典的计算所有不降序列的方法

  1. 在最前方加入一个大小为 \(\sqrt{n}\) 的数
  2. 让已经加入的所有数加 \(1\)

这样就可以考虑到所有的不降序列的,具体转移为

\[g[i][j]=g[i-1][j-\sqrt{n}]+g[i][j-i] \]

其实, \(g[i][j]\) 对应的就是原问题中选了前 \(i\) 个物品,总体积为 \(j\) 的方案数。有了这些,我们就可以统计答案了。设 \(\text{sum}[i]=\sum_{j=\sqrt{n}+1}^{n} g[j][i]\) ,那么答案就是

\[\text{Ans}=\sum_{i=0}^{n}f[\sqrt{n}][i]\times \text{sum}[n-i] \]

整数划分模型

  1. 求把 \(n\) 划分成 \(k\) 个正整数的方案数?
  2. 求把 \(n\) 划分成互不相同 \(k\) 个正整数的方案数?
  3. 求把 \(n\) 划分成 \(k\) 个不大于 \(m\) 的互不相同正整数的方案数?
  4. 求把 \(n\) 划分成 \(k\) 个奇数/偶数的方案数?

问题1

\(f[i][j]\) 表示数 \(i\) 分解成 \(j\) 个正整数的方案数,转移时分为两种情况

  1. 给数 \(i-j\) 所有的 \(j\) 划分的每个数加 \(1\),即 \(f[i][j]\leftarrow f[i-j][j]\)
  2. 给数 \(i-j\) 所有的 \(j-1\) 划分的末尾填上 \(1\),即 \(f[i][j]\leftarrow f[i-1][j-1]\)

理解一下这其实可以讨论到所有的情况

问题2

状态与上一题是一致的,转移如下

\[f[i][j]=f[i-j][j]+f[i-j][j-1] \]

因为要限制没有相同的数字,所以填数的时候必须先给其他所有数加上 \(1\) 之后再填 \(1\) 就不会有相同的情况出现了

问题3

转移方程改成

\[f[i][j]=f[i-j][j]+f[i-j][j-1]-f[i-(m+1)][j-1] \]

减去多余的部分即可

问题4

\(f[i][j]\) 表示将 \(i\) 划分成 \(j\) 个奇数的方案数, \(g[i][j]\) 表示将 \(i\) 划分成 \(j\) 个偶数的方案数,那么有

\[g[i][j]=f[i-j][j] f[i][j]=f[i-1][j-1]+g[i-j][j] \]

CF366C Dima and Salad(分数规划问题与背包)

题目

\(n\) 个水果,每个水果有两个属性:美味值和卡路里值。现在选用若干个(至少 \(1\) 个)水果制作一份特殊的沙拉,沙拉的美味值为所选的水果的美味值的和,沙拉的卡路里值为所选水果的卡路里值的和。沙拉的美味值恰好是卡路里值的 \(K\) 倍。请计算该沙拉美味值最大为多少。

题解

根据 \(a[i] - \text{k}b[i] = 0\) ,我们可以将其看作是一个背包问题,\(a[i]\) 当作是价值,\(a[i]-\text{k}b[i]\) 当作是重量 ,\(0\) 为容量,然后做就行了

\(n\le 100 ,k \le 10\)

CF755F PolandBall and Gifts(贪心+背包)

题目

圣诞节到了,有 \(n\) 个人要互相送礼物。有一个排列 \(p\),第 \(i\) 个人应该把礼物送给第 \(p_i\) 个人(\(p_i \ne i\))。

\(k\) 个人是拖拉机,她们会忘记带礼物,但是我们不知道这些人是谁。一个人能收到礼物,当且仅当她带了礼物,并且应该送给她礼物的人也带了礼物。

给定 \(p, k\),对于所有 \(k\) 个人没带礼物的情况,求最少、最多有多少人能收到礼物。

\(2\le n\le 1\times 10^6,0\le k\le n\)

题解

  • 先考虑收不到的人数最多怎么做。我们将 \(p[i]\) 视作是 \(i\) 集合向外映射的一个集合,相应的我们把它们连上边就组成了一个个的环,我们发现,对于一个大小为 \(s\) 的环只要有 \(\frac{s+1}{2}\) 个人,环内所有人都不会得到礼物了,因此给每个环都这样贪心地做即可
  • 然后考虑收不到的人数最少怎么做。一个显然的贪心是,我们要选一个环就一定要把它选完,因此这变成了选若干个数使得它们的和为 \(k\),如果我们将大小相同的环放在一起,那么这个问题就变成了一个多重背包的问题,直接二进制分组做即可

时间复杂度 \(\mathcal{O}(n\log n)\)

posted on 2023-07-24 19:53  star_road_xyz  阅读(15)  评论(0编辑  收藏  举报

导航