NOIP2024集训Day21 DP常见模型2 - 背包
A. [BZOJ 4987] Tree
树形背包dp
先考虑几个显而易见的性质:
-
选出的点一定是相邻的
-
对于选出的点,如果从 \(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\) 的物品中最大的愉悦度。如果没有这样的物品就是 \(-\infin\)。
询问就把这个区间的所有 \(val\) 取出来,做个完全背包就好了。
两种修改操作用个标记随便搞搞。分别是区间的每个数组平移,和区间加。
复杂度 \(O(nm\log n+q(m^2+\log n))\)。
标签:01,指向,Day21,插入,背包,NOIP2024,节点,DP From: https://www.cnblogs.com/Leirt/p/18396660