NOIP2024集训Day21 DP常见模型2 - 背包

NOIP2024集训Day21 DP常见模型2 - 背包


A. [BZOJ 4987] Tree

树形背包dp

先考虑几个显而易见的性质:

  1. 选出的点一定是相邻的

  2. 对于选出的点,如果从 \(a_k\) 再走回 \(a_1\),那么就相当于每条边经过了两次

由于题目没有包含 \(dis(a_k,a_1)\),因此就相当于选出的点中的一条链可以只经过一次,其余的需要经过两次。

那我们就可以将选点转化为选边,然后考虑树形背包:

\(f_{i, j, k}\) 表示以 \(i\) 为根的子树中选择点 \(i\),共选出 \(j\) 条边,且包含的链端点数目为 \(k\) 的最小代价。

这里解释一下:当 \(k=0\) 时,相当于要从根节点遍历一遍选出的边然后再从根节点出去;\(k=1\) 时,相当于从根节点遍历一遍,到达某链端点后不出去;\(k=2\) 时相当于从某端点遍历到根节点,然后出去再回来到另一端点。

对于根节点与子节点之间的边,显然当 \(k=0\)\(2\) 时计算两遍,否则计算一遍。

这里第二维和第三维都满足背包性质,然后就可以树形背包了。


B. [雅礼集训 2018 Day10] 贪玩蓝月

一个朴素的想法就是模拟这个过程,当询问时做一遍01背包,但这样明显会TLE

想象这样一个例子:当两次询问中间夹着一次插入操作,第二次进行01背包,明显只需要在第一次的基础上对新插入的数做一次01背包

由于 \(p\) 很小,所以这样时间复杂度大大减小

所以我们可以对前端插入与后端插入分别维护一个栈,每次插入时对新插入的数做一次01背包

删除时让栈顶减一即可,因为再次插入时会覆盖这个值

那么当一端已经为 \(0\) 时,再有对该端的删除操作怎么办?

此时将另一端的前一半暴力加入该段即可(另一端也要暴力维护一下)

那么如何查询呢?

枚举一端可能的特征值 \(i\),令 \(L = (l -i + p) \mod p\)\(R=(r-i+p)\mod p\)

则另一端可能的特征值在 \(L\)\(R(R\ge L)\)\(0\)\(R\)\(L\)\(p - 1(R \lt L)\) 之间

用ST表维护区间最值即可


C. [BZOJ3425 POI2013] Polarization

最少可到达点数很好求,就是 \(n-1\)。因为每条边的贡献最少为 \(1\),将树黑白染色,奇数层染黑色,偶数层染白色,所有黑点指向白点,答案就是 \(n-1\)

最多的怎么求?显然是一些点指向一个点,那个点再指向剩下的点(证明最后再说)。

经过中间点的答案就是两边点数的乘积,那么中间点怎么选?显然要使两边点数尽可能相等,选重心就好了。

按01背包来选择一些子树,这样做时间复杂度显然是\(\Theta (n^2)\),我们可以用 bitset 优化成 \(\Theta (\frac{n^2}{32})\),但显然还是过不去。

考虑到子树大小大于 \(\sqrt n\) 的不超过 \(\sqrt n\) 个,所以可以将子树大小大于 \(\sqrt n\) 的暴力DP,剩下的将相同大小的合并后二进制拆分来DP。这样时间复杂度就变成了\(\Theta (\frac{n\sqrt n}{32})\)

最后证明一下为什么一定是找到一个中间点最优:

首先如果改变一棵树中所有边的指向,可到达点对数不变。

如果不是中间点最优,那么一定有一条路径 \(x\) 指向 \(y\)\(x\) 至少有两条出边(假设第二条指向 \(a\)),\(y\) 至少有两条入边(假设第二条入边由 \(b\) 指过来),改变 \(y\)\(b\) 之间的边及 \(b\) 子树中的边或改变 \(x\)\(a\) 之间的边及 \(a\) 子树中的边,一定有一种情况能使答案更优,这样改变下去直到找到一个中间点。


E. [THUPC2018] 弗雷兹的玩具商店

首先每次询问就是完全背包。可以 \(O(m^2)\)

由于每个物品都可以用无数次,所以对于价格相同的物品,我们只用考虑愉悦度最高的。

直接上线段树。\(val_i\) 表示这个区间中价格为 \(i\) 的物品中最大的愉悦度。如果没有这样的物品就是 \(-\infty\)

询问就把这个区间的所有 \(val\) 取出来,做个完全背包就好了。

两种修改操作用个标记随便搞搞。分别是区间的每个数组平移,和区间加。

复杂度 \(O(nm\log n+q(m^2+\log n))\)

posted @ 2024-09-04 15:40  Leirt_Abu  阅读(50)  评论(1)    收藏  举报