伟大 🍏 讲课记录

扫描值域方法

T1 AT_ddcc2017_final_d なめらかな木

给定一棵大小为 \(n\) 的树。你需要统计有多少排列 \(p\),满足对于树上的每条边 \(|p_u-p_v|\le 2\)
\(1\le n\le 50\)
Bonus\(1\le n\le 2\times 10^5\)

考虑从小到大插入所有数,不难知道每个点度数 \(\le 4\),所以我们知道如果 \(p_u=i,p_v=i+1\),然后我们删除这两个点后,最多剩下 \(7\) 个连通块。

不难证明每个连通块里面所有数和 \(i\) 的大小关系相同,这样我们状压每个连通块即可,状态数 \(O(n^22^7)\),转移 \(O(n)\),总复杂度是 \(O(n^32^7)\)

对于 Bonus 则是说的一部分题目中值域的结构会满足特殊性质,这个题中的暂且先不论。但有一些树上问题会有形如子树值域连续,连续的挖掉一个单点,或是互不干扰的若干个区间之类。

T2 P9479 [NOI2023] 桂花树

给定一棵大小为 \(n\) 的有根树,根为 1,标号为 \([1,n]\) 的排列。你要在上面加入 \(m\) 个点,标号为 \([n+1,n+m]\) 的排列。加入后要满足:

  • 对于 \(1 \leq i, j \leq n\),他们的最近公共祖先不变。
  • 对于 \(1 \leq i, j \leq n+m\),在新树上,节点 \(i\)\(j\) 的最近公共祖先编号不超过 \(\max(i,j) + k\)

\(t\) 组数据,答案对 \(10^9 + 7\) 取模。

\(1 \leq t \leq 15, 1 \leq n \leq 3 \times 10^4, 1 \leq m \leq 3000, 0 \leq k \leq 10\)

那么我们就需要 \(1\sim n\) 的虚树保持不变,那么我们可以考虑一个个加点,那么我们发现只有如下情况:

  • 插入作为一个点的儿子。
  • 插在虚树的一条边上。
  • 作为虚树上一条边中间的某个点的儿子。
  • 填在第三种情况的 "某个点" 上。

由于这是有根树,所以不会存在插在根父亲上或者成为根的兄弟的情况。

然后我们就可以 dp 了,\(f_{i,S}\) 表示插入了 \(i\) 个点,有 \(S\) 内部的点是第三种情况的某个点,转移即可,复杂度 \(O(mk2^k)\)

T3 2024 集训队互测 Day6 A. 树数叔术

给定 \(n, m\),对于一棵有标号无根树 \(T\),定义 \(f(T)\) 为满足如下条件的染色方案的方案数,假设 \(i\) 号节点的颜色是 \(c_i\)

  • \(0 \leq c_i \leq m\)
  • 对于所有树上的非空连通块 \(S\) 都要满足 \(\max(\{c_i | i \in S\}) = \min(\{c_i | i \notin S\})\)

特别的,定义 \(\min(0) = m + 1\)

现在要对所有大小为 \(n\) 的有标号无根树 \(T\),对 \(f(T)\) 进行求和,答案对 \(P\) 取模。

\(1 \leq n \leq 150, 1 \leq m \leq 10^9, 3 \leq P \leq 1.01 \times 10^9\)

我们计算无标号,最后乘上 \(n!\) 即可。

我们观察得到,\(m\ge n\) 的时候答案是 \(0\)

然后我们观察一下什么情况合法,对于每个 \(i\)

  • \(i\) 只出现一次。
  • 对于 \([0,i]\) 构成的虚树,不存在 \(i\) 是叶子。

然后我们就可以直接 dp 了,与上一个题不同的是,我们除了维护虚树的形态,然后在虚树边上加点之外,还有一种方法,就是先预计算出虚树边上放多少个点,然后 dp 就很简单了。

T4 AT_dwacon6th_prelims_e Span Covering

有一个区间 \([0, X)\),你有 \(n\) 条线段,第 \(i\) 条长度为 \(L_i\)

对于每条线段你要选择一个非负整数 \(0 \leq j \leq X - L_i\),然后覆盖 \([j, j + L_i]\) 这个区间。

问有多少种选择位置的方式可以覆盖整个区间。答案对 \(10^9 + 7\) 取模。

\(1 \leq n \leq 100, 1 \leq L_i \leq X \leq 500\)

首先有一个容斥做法,钦定部分不能选,然后推一推式子,dp 即可。

更好的做法是按区间长度从大到小插入,然后做连续段 dp。

OI 界背包套路选讲

🍏 写的太好,我直接贺了

0-1 背包

无价值:给定 \(n\) 个物品,第 \(i\) 个体积为 \(c_i\)。问能否选出一些物品,使得体积和为 \(m\)

直接套 Jumping sequence 时间复杂度 \(O(nc)\)

\(c = \max(c_i)\),考虑找到一个断点 \(p\),使得 \(\sum_{i=1}^p c_i\)\([m - c, m + c]\) 之间。

然后考虑一边加入物品一边删除物品,当体积小于 \(m\) 时,尝试加入一个物品,否则尝试删除一个物品。记录 \(g(i, x)\) 表示加入了前 \(i\) 个物品,体积和为 \(x\),最多有前多少个物品可以回退,如果无解则值为 \(-1\)

初始令 \(g(p, \sum_{i=1}^p c_i) = p\),其他为 \(-1\),随后不难发现有如下转移:

\(\forall x \in [m - c, m + c], g(i - 1, x) \rightarrow g(i, x)\)

\(\forall x \in [m - c, m], g(i - 1, x) \rightarrow g(i, x + c_i)\)

\(\forall x \in [m, m + c], j \in [1, g(i, x)], j - 1 \rightarrow g(i, x - c_j)\)

但这样复杂度仍然是 \(O(n^2c)\),实际上复杂度并没有获得优化,但是不难发现 \(j\) 实际上不需要枚举这么多,对于 \([1, g(i, x)]\) 中的所有值,实际上 \([1, g(i - 1, x)]\) 已经在之前被枚举过了,因此只枚举 \((g(i - 1, x), g(i, x))\) 即可,即将第三条转移改为:

\(\forall x \in [m, m + c], j \in (g(i - 1, x), g(i, x)], j - 1 \rightarrow g(i, x - c_i)\)

不难发现,对于同一个 \(x\)\(g(i, x)\) 关于 \(i\) 单调,且 \(j\) 的枚举量为 \(\sum_{i=p+1}^n g(i, x) - g(i - 1, x)\),其实即为 \(g(n, x) - g(p, x)\)。不难发现 \(g(n, x)\)\(O(n)\) 的。因此时间复杂度 \(O(nc)\)

Bonus:问题同上,但给定 \(m\) 后,对于所有 \([0, m]\) 内的都要求

时间复杂度 bitset \(O(\frac {mn}w)\) 或者分治 FFT \(O(nc\log^2 n)\)

有价值:给定 \(n\) 个物品,第 \(i\) 个体积为 \(w_i\),价值为 \(v_i\)。你需要选出一些物品使得体积不超过 \(m\),并最大化价值和。
\(w = \max(w_i), v = \max(v_i)\)
shuffle,然后背包 \(O(n\sqrt n w)\),或者每种权值跑决策单调性 \(O(wm)\)

复杂度为 \(O(n\sqrt{n}w)\) 的做法一:

  • 考虑找到一个断点 \(p\),使得 \(\sum_{i=1}^p w_i\)\([m - w, m + w]\) 之间,然后直接选上前 \(p\) 个物品,并将这些物品的体积和价值取反。
  • 然后将所有物品随机打乱,并依次加入,期望只需要背包体积在 \([m - O(\sqrt{n})w, m + O(\sqrt{n})w]\) 内的结果即可。
  • 似乎如果第一步先按性价比取,后续调整只会卡到 \(O(w\sqrt{w})\)。不清楚。

复杂度为 \(O(wm)\) 的做法二:

  • 考虑同一体积的一起加入。令 \(f(i,x)\) 表示加入了体积 \([1,i]\) 内的物品,体积为 \(x\) 的最优解。
  • 考虑加入体积为 \(i\) 的物品时,将 \(f(i-1,x)\) 按照 \(x \bmod i\) 分类,然后就相当于每一类内做 \(\max +\) 卷积,由于体积为 \(i\) 的物品加入情况是凸的,因此复杂度 \(O(wm)\)
  • 这个做法慢的没边,也不怎么牛,请勿轻易尝试。

完全背包

无价值:给定 \(n\) 类物品,每类有无限个,第 \(i\) 类体积为 \(c_i\)。问能否选出一些物品,使得体积和为 \(m\)
\(c = \max(c_i), g = \gcd(c_i), z=\min(c_i)\)
跑同余最短路,绕圈即可,复杂度 \(O(nz)\)

首先当 \(m\) 足够大时,\(m\)\(g\) 的倍数即可,否则一定不行。界是 \(O(c^2)\) 的。

\(m\) 不够大时,我们有如下手段,然后对于 \(x \in [0,z)\)\(f(i,x)\) 表示加入了前 \(i\) 个物品,模 \(z\)\(x\) 的体积和中最少可以凑出 \(f(i,x)\)

然后直接进行转移,初始令 \(f(0,0) = 0\) 即可。每次转移对于 \(\gcd(c_i,z)\)\(x\) 分类并进行转移,至多只会绕两圈,因此复杂度 \(O(nz)\)。你会发现非常奇怪,这个东西复杂度和最小的体积有关,但事实就是如此。

讲完绕圈我们回去分析界,实际上可以分析到 \(O(zc)\)。核心在于对于某个 \(f(i,x)\),考虑假设有 \(m\) 个物品,并对他们体积做前缀和,依次为 \(p_0,p_1,\ldots,p_m\)。那么如果 \(m\) 大于等于 \(z\),必然有两个 \(p\)\(z\) 同余,此时删掉这个区间内的物品即可。因此有 \(m \leq z\)

有价值:给定 \(n\) 类物品,每类有无限个,第 \(i\) 类体积为 \(w_i\),价值为 \(v_i\)。你需要选出一些物品使得体积不超过 \(m\),并最大化价值和。
\(w = \max(w_i), v = \max(v_i)\)。令性价比最优的物品体积价值分别为 \(w_{\max}, v_{\max}\)
\(m\) 超出 \(O(w^2)\) 的时候,可以考虑套用绕圈法,复杂度 \(O(nw)\)
\(m\) 不够大。
一种做法是分治,可以解决刚好选 \(k\) 个的问题。
剩下一种是我们对于 \(f_i\) 表示体积为 \(i\) 最多的价值和,则我们只需要保留性价比 \(\min(\frac {w^2}i,n)\) 的即可,这样可以求出所有的解。
两种做法复杂度都是 \(O(w^2\log w)\)

多重背包

无价值:给定 \(n\) 类物品,第 \(i\) 类体积为 \(c_i\),有 \(k_i\) 个。问能否选出一些物品,使得体积和为 \(m\)
有点震撼,下面细说:\(O(\frac {n^2c^2\log c}w)\)

\(c = \max(c_i), s = \sum_{i=1}^n c_ik_i\),当 \(s\)\(O(nc^2)\) 或以下时考虑暴力处理,否则有如下结论:

  • 当存在 \(p\) 使得 \(k_p \geq c\) 时,那么在 \([nc^2, s-nc^2]\) 内对于是否可以取出来有周期 \(c_p\)

考虑如果 \(x\) 能取出来,但 \(x+c_p\) 取不出来,那么此时 \(p\) 一定选了 \(k_p\) 个,由于在周期内,一定存在一个其他物品少取了至少 \(c\) 个,假设其为第 \(i\) 类,则第 \(p\) 类可以少取 \(c_i\) 个,而第 \(i\) 类物品多取 \(c_p\) 个即可。答案数组显然翻转后对称,因此对于证明 \(x-c_p\) 能取出来是一样的。于是我们只要求解 \(O(nc^2)\) 内的答案。

如果不存在则 \(s\)\(O(nc^2)\),是一样的。

用 bitset 加二进制分组优化,复杂度 \(O(\frac {n^2 c^2 \log c} w)\)

有价值:给定 \(n\) 类物品,第 \(i\) 类体积为 \(w_i\),价值为 \(v_i\),有 \(k_i\) 个。你需要选出一些物品使得体积不超过 \(m\),并最大化价值和。
可以对于每个物品,只拿 \(w\) 个数背包,dp 完后对于每个 \(f_i\),贪心的选剩下的部分做到 \(O(n^2w^2)\)
或者二进制拆分,只保留从大到小考虑,只考虑有意义的部分的数组 \(O(n^2w\log k)\)
不难发现上面两个部分都可以把 \(w\) 变成 \(v\)

复杂度为 \(O(n^2 w^2)\) 的做法一:

  • 首先,我们考虑先将 \(k_i\) 缩小到 \(O(w)\)​ 级别,每次我们只拿出 \(w\) 个物品进行动态规划,而剩余的直接按照性价比贪心去取。
  • 为什么这个是对的呢?我们假设最优的决策中第 \(i\) 个物品选择了 \(x_i\) 个,你发现,在最优的决策中,一定不会出现一对 \((i, j)\),满足 \(\frac {v_i} {w_i} > \frac {v_j} {w_j}, x_i \leq k_i - w, x_j \geq w\),否则可以将 \(c_i\) 个物品 \(j\) 换成 \(c_j\) 个物品 \(i\),此时价值不变,体积变小。
  • 那么不难发现,最优的情况一定会被计算到。

复杂度为 \(O(n^2 w \log k)\) 的做法二:

  • 我们考虑拆位,并进行数位动态规划。先对于每个 \(k_i\),通过二进制分组将其拆成 \(O(\log k_i)\) 个物品。
  • 对于新的每个物品,假设其对应了原来的 \(2^\alpha\) 个物品,就放入第 \(\alpha\) 层。
  • 然后我们从大往小去动态规划,记录 \(f_{\alpha, x}\) 表示考虑了 \(\alpha\) 即以后的层,体积和为 \(2^\alpha x\) 的情况下,最大的价值和。
  • 你会发现对于剩余的层的物品,总体积都不超 \(2^\alpha \times \sum w_i\)。所以每层只需要保留 \(O(\sum w_i)\)\(O(nw)\) 个状态。
  • 因此复杂度 \(O(n^2w \log k)\),这个做法也可以替换成 \(O(n^2 v \log k)\),手段近似的,转为只需要保留几个价值和最大且满足 \(m\) 限制的 \(O(\sum v_i)\) 个状态。

可以通过一些手段,类似做法一的操作把做法二的 \(\log k\) 换成 \(O(\log w)\)。但意义不大,而且很唐。

树上背包

体积任意的树上背包:树上的每个结点是一个物品,第 \(i\) 个点体积为 \(w_i\),价值为 \(v_i\)。你需要选出一些物品使得体积不超过 \(m\),并最大化价值和。

这类问题往往的没边,这里就列一些经典的东西。

如果仍然到树上去跑,由于避免不了 \(\max +\) 卷积,往往必然带 \(O(m^2)\) 的复杂度,如下是一些手段,去消去 \(m\) 上的指数。

\(m\) 通解科技:HLRecDp

该算法用若干个的 \(n\) 去代替 \(m\),实际上运用性不高,但你就说去没去 \(m\) 吧。

讲的很抽象,看不懂,大概就是如果需要 dp \(k\) 个背包,每个背包之间相互依赖,大小都是 \(m\),那么我们可以树上启发式合并在 \(k>1\) 时做到 \(O(n^{\log_2(k+1)}m)\)\(k=1\) 做到 \(O(nm\log n)\)

posted @ 2025-04-11 11:00  Nityacke  阅读(116)  评论(1)    收藏  举报