11月杂题

CF1763F Edge Queries

第一想法是缩边双,但是画个图发现有些情况不好处理。

于是我们考虑缩点双,建出圆方树。考虑 \(a\to b\) 简单路径上的所有点双,若其不为两点一边,则删去任意一条边均能联通。

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

CF2005D Alter the GCD

扫左端点 \(l\),对于右边形成本质不同的 \(\log V\)\(\gcd\) 区间的右端点依次考虑。设它们分别为 \(r_1<r_2<\dots <r_t\)

对两个序列分别求出本质不同的后缀 \(\gcd\) 以及其左端点,找到 \((r_{j-1},r_j]\) 之间的所有这样的左端点 \(p_k\) 依次考虑。此时序列被分割为 \([1,l)\cup [l,p_k]\cup (p_k,n]\),选择方案有 \(p_{k+1}-p_k\) 种。

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

CF2005E2 Subtangle Game (Hard Version)

先考虑 Easy Version。

\(f_{i,j,k}\) 表示现在面对 \((i,j)\sim (n,m)\) 的矩阵,是否能赢。

\(f_{i,j,k}=1\) 当且仅当满足以下其中一个条件:

  • \(a_{i,j}=b_k\) 时,\(j=m\)\(i=n\)\(k=l\)\(f_{i+1,j+1,k+1}=0\)
  • \(\exist x,y,s.t. f_{x,y,k}=1\)

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

考虑优化,我们发现若 \(f_{x,y,k}=1\) 则所有 \(i\le x,j\le y\) 都满足 \(f_{i,j,k}=1\)。所以所有 \(1\) 的位置构成一个上阶梯状。我们考虑记 \(g_{i,k}\) 表示第 \(i\) 行最大的满足 \(f_{i,j,k}=1\)\(j\)\(mx_{i,k}\) 表示第 \(i\) 行最大满足 \(a_{i,j}=b_k\)\(j\)。然后直接转移就好了。

这依赖一个结论,就是 \(b\) 在某个数第二次出现的时候就一定失败。因为若有多个候选项一定会选择最右下角那个。

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

反思:我不够智慧。

CF1936C Pokémon Arena

对于每种属性,从高到低依次连边,正边权为 \(a_{i,j}-a_{i+1,j}\),负边权为 \(0\)

每种属性向对应的宝贝连边,入边边权设为 \(c_i\)

点数是 \(nm+n\),边数是 \(2nm+2nm\)

有点像差分建边,不是很难。

CF1860E Fast Travel Text Editor

将两个字符的中间看成一个点,点权两个字符组合的哈希值,设点为 \(p_i\),点权为 \(a_i\)。则 \(p_i\)\(p_{i-1}\) 连双向边,边权为 \(1\)\(p_i\to a_i\),边权为 \(1\)\(a_i\to p_i\),边权为 \(0\)

直接 01BFS 复杂度无法接受。

观察到虚点数量很少,考虑以虚点为中转站。预处理从某个虚点走出去的最短路和走进来的最短路。然后枚举虚点取 \(\min\) 即可。

[ARC173D] Bracket Walk

有点高级了。

\((\) 视作 \(1\)\()\) 视作 \(-1\)

注意到如果一个环上和为 \(0\),则肯定可以选择一个起点绕环一圈形成一个合法的括号序列。也就是说,如果全是 \(0\) 环,则可以实现。

若既有正环也有负环也行。因为可以通过改变绕圈次数抵消。

使用 Bellman-Ford 算法解决。

反思:该种题目可以考虑从的角度切入。操作过于抽象的时候,要敢于猜测结论,努力寻找充要条件。

[ARC171D] Rolling Hash

牛逼题。

首先这个区间 hash 我们用平常的视角也考虑转成差分的形式。设 \(s_i\) 表示后缀哈希值,则 \(\operatorname{hash}(l,r)=B^{r-n}(s_l-s_{r+1})\)。所以 \(\operatorname{hash}(l,r)\ne 0\) 的充要条件就是 \(s_l\ne s_{r+1}\)

此时我们关注的就只是 \(s_i\),跟序列和 \(B\) 没有半毛钱关系。于是我们将 \(l,r+1\) 之间连边,现在只需要给每个点染色,要求连边的不能染成同一种颜色,最后是否能用不多于 \(P\) 种实现。DP 即可。

反思:做题时要清楚自己需要的是什么,对于无关的不要想太多。遇到有区间限制的,要尝试转成差分形式。

[ARC169C] Not So Consecutive

\(f_{i,j}\) 表示第 \(i\) 个 数填了 \(j\)。然后枚举连续段的起点转移。

第一个没填 \(j\) 的位置是可以直接找到的,记其为 \(p\)。则 \(\sum\limits_{k=p}^{i-1}\sum \limits_{j'\ne j}f_{k,j}\to f_{i,j}\)

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

但是我写的太shi了,还过不去样例。不应该把 \(-1\) 拿出来单独做,应该直接在原序列做这样简便一点。

反思:要寻找实现简便的方式写代码。

CF1699E Three Days Grace

考虑固定最小值,求最小的最大值。

\(f_x\) 表示将 \(x\) 分解成不小于 \(mn\) 的若干个因数相乘的最大因数的最小值,答案即 \(\max\limits_{x\in A}f_x -mn\)

\(mn\) 变化的时候 \(f\) 如何变化?

\(mn+1\to mn\) 时,显然只有 \(mn\) 的倍数发生变化。对这些倍数重新做一遍。复杂度是调和级数。

CF1584F Strange LCS

先考虑每种字母只出现一次怎么做。

此时如果我们枚举 LCS 的末尾,则可以直接定位到某个字符串的某个具体位置,直接将子问题的范围限制住了,非常的舒服。于是可以设 \(f_{i,j}\) 表示长度为 \(i\) 的 LCS,结尾为 \(j\) 是否可行。定位到 \(n\) 个字符串 \(j\) 所在的位置,然后枚举上一个字符 \(k\),看在 \(n\) 个字符串里, \(k\) 是否均在 \(j\) 的前面,若可以,则 \(f_{i-1,k}\to f_{i,j}\)。答案即最大的 \(i\) 满足 \(\exist j,s.t.f_{i,j}=1\)。时间复杂度 \(\mathcal{O}(Tlen\times |\Sigma|^2n)\)

当出现两次后,直接记录最后一个字符是什么显然不行,还需记录最后一个字符是第 \(i\) 个字符串的第一个还是第二个。这个可以直接状压出来,于是我们将状态改为 \(f_{i,j,s}\) 表示长度为 \(i\) 的 LCS,结尾为 \(j\),状压出来的状态是 \(s\) 是否可行。像上述方法一样转移:枚举上一个字符 \(k\),贪心地优先取第二个,不合法才取第一个。然后 \(f_{i-1,k,s'}\to f_{i,j,s}\)。时间复杂度 \(\mathcal{O}(Tlen \times |\Sigma|^2n2^n)\)

这样仍然无法通过。注意到 \(f\) 的转移是存在顺序的,将其看作子序列自动机就是一个 DAG。于是可以省去第一维,直接记 \(f_{j,s}\) 表示以 \(j\) 结尾,状态为 \(s\) 的最长长度。为了满足转移顺序,使用记忆化搜索,时间复杂度 \(\mathcal{O}(T|\Sigma|^2n2^n)\)

反思:当需要使用题目给的“特殊性质”入手时,如果仍然不会做,可以尝试继续将“特殊性质”简化。

[ARC170C] Prefix Mex Sequence

这辈子都做不出一个关于 Mex 的题目。

首先当 \(m\ge n\) 的时候,无论如何 mex 都不会超过 \(m\),于是对于每个 \(a_i=0\) 的地方都有 \(m\) 种选法(不选 mex)。直接算就好了。

否则,一开始直接在状态里记 mex 的值,但这样存在后效性。所以考虑将这个 mex 转化。

我们想要换一种方式刻画这个 mex 的操作。我们并不关心 mex 的具体值。假设现在有 \(m+1\) 个格子,填了一些格子。如果 \(a_i=1\),意味着要在最左边的没有填的格子填数。否则,可以在其他任意一个格子填。

于是直接设 \(f_{i,j}\) 表示前 \(i\) 个数填了 \(j\) 个格子,转移不表。

反思:遇到这种抽象的很烦的操作一定要转化题意,换一种方式刻画。

[ARC170D] Triangle Card Game

\(A,B\) 从小到大排序。

设选择的三个数分别是 \(a,b,c\)。则需要满足 \(|a-b|<c<a+b\)

把绝对值去掉,分类讨论:

  • \(b\le a\)

    此时 \(b\) 要尽量小,\(c\) 的范围才最小。如果存在合法的 \(c\) 那和 \(a\) 相邻的两个中必有一个可以。直接判断即可。

  • \(b>a\)

    此时 \(c\in (b-a,b+a)\)。可以证明,\(a\) 取更大的数是不劣的。

所以,先选出满足第一种情况的最大的 \(a\),再判断是否第二种合法。

[ABC373F] Knapsack with Diminishing Values

\(f_{i,j}=\max f_{i-1,j-kw_i}+kv_i-k^2\)

这个 \(k^2\) 提示我们可以斜率优化,尝试把 \(k\) 换成用第二维状态表示出来的东西。考虑把 \(j\)\(\bmod w_i\) 分类,然后单调队列就好了。

CF1051E Vasya and Big Integers

\(f_i=\sum\limits_{l\le s(i,j)\le r} f_{j+1}\)

决策点是一段区间。

问题在于怎么快速比较大数字的大小。用哈希,每次折半。

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

CF1895F Fancy Arrays

妙。

首先想着怎么把第一个条件转化掉,发现 \([x,x+k-1]\) 的区间长度为 \(k\),而 \(|a_i-a_{i-1}|\le k\)。因此只需 \(\min a_i\le x+k-1,\max a_i\ge x\) 即可。

容斥一下变成 \(\min a_i\le x+k-1\) 减去 \(\max a_i < x\)

  • 第一部分,因为只要确定了 \(\min a_i\) 和差分数组就能唯一确定 \(a\),于是直接 \(\min a_i\times (2k+1)^{n-1}\)
  • 第二部分,做一个 DP。设 \(f_{i,j}\) 表示前 \(i\) 个数最后一个数为 \(j\) 的方案数。然后矩阵优化一下。

反思:遇到 \(\exist i,s.t.\dots\) 类似的条件要尝试转化,可以转成和最大最小值相关的。也可以从 \(x\le 40\) 联想到最大最小值。\(|a_i-a_{i-1}|\) 这样的条件要联想到差分数组。

[ARC168C] Swap Characters

直觉告诉我们,应该从最后的字符串出发,找到最简便的交换方式然后计数。

最简便的交换方式肯定是先交换能两两匹配的,再交换一个全排列。

于是直接枚举 \(ab,ac,bc\) 还有全排列的交换次数就好了。

有些细节。

反思:做题时要相信自己直觉。

P11255 [GDKOI2023 普及组] 淋雨

\(t_i,p_i\) 分别表示落地时间和落地位置。按 \(t_i\) 从大到小排序然后 DP。

\(f_i\) 表示第一个淋雨的是第 \(i\) 个雨滴。转移考虑下一个走得过去的雨滴 \(j\),然后 \(f_j+1\to f_i\)

能走过来的条件是 \(|p_i-p_j|\le v(t_j-t_i)\),分类讨论:

  • \(p_i>p_j\)

    \(p_i+vt_j\ge p_j+vt_j\)

  • \(p_i<p_j\)

    \(p_i-vt_i\le p_j-vt_j\)

直接 CDQ 分治优化 DP 即可。

P7530 [USACO21OPEN] United Cows of Farmer John P

\(lst_i,nxt_i\) 分别表示上一个/下一个和 \(i\) 相同的位置。

\(f_{l,r}=\sum\limits_{j=l+1}^r[lst_j<l][nxt_j>r]\)。扫右端点 \(r\),贡献是 \(\sum\limits_{l=lst_i+1}^{r-2}[nxt_l>r]f_{l,r-1}\)

扫描线,假设现在右端点是 \(i\),操作流程如下:

先查询 \([lst_i+1,i-2]\) 有用\(f\) 和,贡献到答案。

\([lst_i+1,i-1]\) 之间有用\(f\) 全部加一。

\([lst_{lst_i}+1,lst_i-1]\) 之间有用\(f\) 全部减一。

\(lst_i\) 处的 \(f\) 值置为无用,\(i\) 处的 \(f\) 值置为有用。

用线段树维护 \(f\)。维护 \(s,cnt\) 分别表示有用的 \(f\) 和、个数。时间复杂度 \(\mathcal{O}(n\log n)\)

[ARC167C] MST on Line++

将边权为 \(i\) 的边称为 \(i\) 类边。考虑每条边被选了几次。

考虑 kruskal 的过程,这只和边权的相对大小有关,所以将 \(a_i\) 升序排序。

考虑如下的子问题:

\(|i-j|\le k\)\(\max (p_i,p_j)\le A\) 时有边,求不形成环的情况下最多能选多少条边。

\(f_i\) 表示 \(A=i\) 时的答案,第 \(i\) 条边被选的次数就是 \(f_i-f_{i-1}\)

怎么求 \(f_i\)?对于一个排列 \(P\),将 \(P_j\le i\) 的下标 \(j\) 放进集合 \(Q\)\(Q\) 中元素升序排序。不在 \(Q\) 集合里的点一定没有任何连边。

而所有 \(Q_j-Q_{j-1}\le k\) 的下标之间都有连边,都选上一定不劣。所以一个排列 \(P\) 的贡献就是 \(\sum\limits_{j=2}^i [Q_j-Q_{j-1}\le k]\)

枚举一个 \(j\),对所有排列计算贡献,\(Q_j-Q_{j-1}\le k\) 的排列有 \(\sum\limits_{K=1}^k\binom{n-K}{i-1}\times i!\times (n-i)!\) 个。再乘上 \((i-1)\) 即可。

反思:步步紧凑的计数题,难度还是灰常大的。和某些算法要解决的问题相关的题目,可以从算法的过程入手。

[ARC067E] Grouping

按组的大小从小到大考虑。

\(f_{i,j}\) 表示考虑了 \(i\) 个人,最后一组的人数为 \(j\) 的方案数。转移即枚举人数为 \(j\) 的组的总人数,\(\sum\limits_{k=1}^{j-1}f_{i,j}\times \binom{n-i}{k-i}\times g_{k-i,(k-i)/j}\to f_{k,j}\)。其中 \(g_{i,j}\) 表示将 \(i\) 个人平均分成 \(j\) 组的方案数。

时间复杂度 \(\mathcal{O}(n^2\ln n)\)

P7297 [USACO21JAN] Telephone G

不会分层图。

\(k\le 50\) 启发我们要用分层图,但是怎么设计这个图。

\(|i-j|\) 这样的边权启发我们对每一层都建出一条链,然后 \((b_i,i)\to i\) 连一条边,\(i\to (c,i)(S_{b_i,c}=1)\) 连一条边。

反思:优化建图的时候,怎么建模可以可以从边权角度入手。

P6008 [USACO20JAN] Cave Paintings P

考虑求出所有联通块内部的方案数,再相乘。

先跑一次并查集将所有联通块找出来。

从下往上考虑,从初始开始合并联通块。对于第 \(k\) 行,记 \(v_i\) 表示第 \(i\) 个联通块的形态个数。然后找出最终在第 \(i\) 个联通块但现在还没有合并的所有 \(i_1,i_2\dots i_t\),则 \(\prod\limits_{j=1}^t v_{i_j}\) 是只考虑行数 \(\ge k\) 的贡献。容斥一下,记 \(f_{i,j}\) 表示最终第 \(i\) 个联通块在第 \(j\) 行的答案,将 \(\prod v_{i_{j}} -f_{i,k+1}\to f_{i,k}\)

每个联通块的答案就是 \(\sum\limits_{k=1}^n f_{i,k}\)

如何维护 \(v\) ?同样使用并查集,每次将下一行的 \(v\) 相乘,合并完再加 \(1\)(表示选上这一行)。

P6010 [USACO20JAN] Falling Portals P

神题。

一瞬间想过要凸包,但是想法转瞬即逝。

这个题应该往贪心上面去想,因为显然具有一些优秀性质。

\(A_{Q_i}<A_i\) 时,应该尽可能快的往下走,否则应该尽可能慢的往下走。

把所有点拍到平面上变成直线,交点就表示相遇。

只考虑前者。容易发现从 \(i\) 点出发到达的地方是一个凸包,并且 \(A_j<A_i\) 的世界没有用。所以按 \(A_i\) 从大到小的顺序插入直线,由于截距单调所以单调栈维护凸包即可。查询时直接二分直线与凸包交点即可。

[ARC187B] Sum of CC

首先可以发现,联通块是一段区间。那么容易想到把每个区间的贡献拆出来。

一开始想的是枚举区间,然后快速计算贡献,然后发现这个区间贡献很难快速计算。

但其实我们可以只看断点,\(i\)\(i+1\) 不联通的充要条件就是 \(\min(A_1,\dots A_i)>\max(A_{i+1},\dots A_n)\)。 所以直接枚举 \(\min\) 然后算就好了。

反思:把题目转化的太复杂,应该寻找更简单的转化方式,让条件的式子更简洁。

[ARC187D] Many Easy Optimizations

再次在极差问题中倒下。

应该还是考虑固定最小值,求最小的最大值。

\(f_i\) 表示当最小值为 \(i\) 时,最大值最小为多少。答案则 \(\min f_i-i\)

当加入 \(a_i,b_i\) 时,考虑 \(f\) 的变化。不妨设 \(a_i\le b_i\)

\(p\) 表示最大的 \(j\) 满足 \(f_j< a_i\),则 \(f_{1\sim p}\leftarrow a_i\)\(f_{p+1\sim a_i}\) 不变。

\(q\) 表示最大的 \(j\) 满足 \(f_j<b_i\),则 \(f_{a_i+1\sim q}\leftarrow b_i\)\(f_{q+1\sim b_i}\) 不变。

\(f_{b_i+1\sim\infty}\leftarrow +\infty\)

离散化后线段树优化,时间复杂度 \(\mathcal{O}(n\log n)\)

反思:切记遇到极差相关的都可以考虑固定最小值。或者说遇到跟两个变量相关的都可以考虑固定某一个。

P11268 【MX-S5-T2】买东西题

对于 \(i\) 无非就三种选择:

  • 使用 \(b_i\)
  • 用一张没用过的优惠券。
  • 从前面抢一张优惠券。

一开始想的是在第二种情况失效的时候反悔,但其实应该是对后面两种情况整体反悔。因为后两种情况是同一种,应该放在一起。

反思:反悔贪心的时候要思考清楚贪心操作的类型,将同类的放在一起。

P3546 [POI2012] PRE-Prefixuffix

首先满足条件的前后缀应该包含了一个 Border。

可以 KMP 求出所有 Border 的位置,然后又是求一个 Border。

显然不能再求一次。要找性质。记 \(s_i=S[i+1:i-n]\),我们现在要求的就是 \(s_i\) 的 Border。考虑它与 \(s_{i+1}\) 的关系,发现 \(|B_{\max}(s_i)|\le |B_{\max}(s_{i+1})|+2\)

于是我们可以从大到小枚举 \(i\),维护 \(l\) 表示 \(s_i\) 的最长不重叠 Border。\(l\) 移动次数 \(\le 2n\)

反思:字符串的题要仔细找性质。

P6072 『MdOI R1』Path

怎么刻画路径不交这个限制?

注意到如果我们选定一个点 \(u\),钦定 \(a,b\)\(u\) 的子树外,\(c,d\)\(u\) 的子树内,则这覆盖了所有的情况。

\(v_i\) 为前缀异或和,则 \(f(E(x,y))=v_x\oplus v_y\)。设 \(s_i,t_i\) 分别表示 \(i\) 子树内/外的最大异或和,则问题转化为 \(\max s_i+t_i\)

\(s_i\) 可以 01Trie + DSU on tree。

\(t_i\)P8511

  • 首先求出全局最大异或和,那么只有 \(x\to 1,y\to 1\) 这两条路径上的点答案不是全局最大异或和。

    于是从根节点往下走到 \(x\),途中不断加入点,每个点只会被加一次,时间复杂度 \(\mathcal{O}(n\log n)\)

然后把两部分拼起来即可。

反思:当遇到像「路径不交」这样奇怪的限制不会刻画时,可以尝试和图本身游戏相关的东西去作为分类依据,将东西分为两部分。P8511 给我们的启发是,遇到熟悉的问题加强版,可以尝试先沿用原先的做法,再在原先的做法上处理一些特殊的情况。

P3245 [HNOI2016] 大数

这也是莫队。

区间问题不好直接解决,就要转成差分的形式。设 \(t_i\) 表示 \(i\sim n\) 构成的数字。若 \(l,r\) 合法则 \(\dfrac{(t_l-t_{r+1})}{10^{r-l+1}}\equiv 0\pmod p\)

\(p\ne 2,5\) 时,可以将分母直接去掉,转成 \(t_l=t_{r+1}\) 的计数,莫队即可。

反思:区间计数要时刻记得差分这个选项。

CF1511G Chips on a Board

显然可以转化成 Lim 博弈。

可以离线,尝试套一个莫队上去。

现在要求支持全局 \(+1/-1\),全局异或和,插入删除一个数。

跟二进制有关的都可以思考 Trie 树。我们考虑倒着建 Trie。每次 \(+1\) 就相当于交换 \(0,1\) 的边,然后递归 \(0\) 的边。

时间复杂度 \(\mathcal{O}(n\sqrt{n}\log n)\)。需要卡常。

考虑一种更优秀的做法。

因为跟位运算有关,考虑逐位确定答案。而逐位这种东西用倍增维护非常方便。

\(f_{i,j}\) 表示钦定左边界为 \(i\)\([i,i+2^j-1]\) 这个区间的异或和。从 \(f_{i,j}\to f_{i,j+1}\) 的时候,你发现第 \(j\) 位的贡献只和 \([i+2^j,i+2^{j+1}-1]\) 有关,所以可以直接转移。

算答案的时候,也是像倍增一样从高到低拆区间。每次拼上一段区间,还未被拼上的区间的距离就会加上一个二的幂次,也就是说这只会对答案的某一位产生贡献,所以也可以处理。

反思:跟位运算有关的可以思考 Trie,倍增(固定了一个端点)。当然也要会莫队的骗分方法。

P4287 [SHOI2011] 双倍回文

唐完了。

枚举中心点 \(i\),则需要在 \([(i+i-p_i+1)/2,i]\) 里找一个最小的 \(j\) 满足 \(j+p_j-1\ge i\)。套一个 CDQ 即可。

显然无需这么麻烦。因为当 \(i\) 从小到大增加时,\(j+p_j-1<i\) 的点就完全无用了。所以拿两个 set 维护一下,每个点只会被插入删除一次,时间复杂度 \(\mathcal{O}(n\log n)\)

CF576E Painting Edges

线段树分治。

首先多种颜色互不影响,所以可以对每种颜色开一个加权并查集,然后还要可撤销。

问题是我们不知道一条边存在的时间区间。

可以考虑边判断边修改,复杂度仍是对的。

CF gym102354 B

神仙题。

首先绝对值可以拆成 \(\max(a_i-b_j,b_j-a_i)\)。这样我们只需正反做两次即可。稍微取个相反数变成 \(\max (a_i+b_j)\)

但是看上去仍然不可做。

经典的 \(\gcd\) 卷积暴力做很优,所以我们也考虑暴力

\(c_k=\max\limits_{i\mid k}^n\{a_i+\max\limits_{\gcd(i,j)=k }^n b_j\}=\max\limits_{i\mid k}^n\{a_i+\max\limits_{i/k\perp j/k }^n b_j\}\)

\(=\max\limits_{i=1}^{n/k}\{a_{ik}+\max\limits_{j=1}^{n/k} b_{jk}[i\perp j] \}\)

考虑把每个 \(k\) 拿出来单独做,也就是说要求快速查询 \(\max\limits_{i=1}^m b_i[i\perp t]\)

这个 \(\max\) 很烦。于是考虑转化成判定性问题,多组询问考虑整体二分。

二分答案 \(C\),只需判定 \(\sum\limits_{i=1}^m [C\le b_i][i\perp t]>0\) 即可。

求和我们就可以一顿操作了,转化成

\(\sum\limits_{d\mid t} \mu(d) \sum\limits_{d\mid i}^m [C\le b_i]\)

我们需要写一个数据结构,支持求某个数倍数处点权和,带修。

直接枚举约数就好了。修改是 \(\mathcal{O}(d_i)\) 的。做一个 \(k\) 的复杂度就是 \(\mathcal{O}(\log m\sum\limits_{i=1}^m d_i)=\mathcal{O}(m\log^2 m)\)

总的复杂度为 \(\mathcal{O}(\sum\limits_{k=1}^n (n/k)\log ^2(n/k))=\mathcal{O}(n\log^3 n)\)

反思:先是套路的拆绝对值,然后从暴力入手,将 \(\max\) 转化成判定性问题,再套上整体二分。对基本功要求极高。

P4606 [SDOI2018] 战略游戏

圆方树。

建出圆方树后,就是两两关键点之间的圆点的并集。

这样很难做,考虑转化成最小的包含所有关键点的联通块的圆点数量减去关键点数量。

那又怎么求出这个最小联通块呢?将圆点点权设为 \(1\),方点设为 \(0\)。我们使用处理树上问题的利器:dfs 序!

拍到区间上,将关键点按 dfs 序排序,我们惊奇地发现,如果按照 dfs 序从小到大走过每个点,然后走回第一个点。在走过的路径中不算 \(\rm LCA\),那么每个点恰好被走了两次(除了第一个和最后一个的 \(\rm LCA\))。于是树上倍增即可。

反思:dfs 序好帮手,要认真考虑。

P10408 「SMOI-R1」Apple

典题,直接 meet in middle。

\(k=n/2\)。预处理出 \(f_s\) 表示前 \(k\) 位和 \(s\) 一样,后面的是 \(s\) 子集的子集和。用 SOS DP 可以做到修改查询 \(\mathcal{O}(2^{n/2})\) 平衡。

也想过对 \(|S|\) 根号分治,但是没想出来,简单写一下:

  • 对于询问,若 \(|S|\le k\),可以直接枚举子集。否则,其补集较小,可以容斥。枚举补集的一个子集,钦定包含了他。
  • 也就是说,要额外维护 \(|S|\le k\) 的所有超集权值和,记为 \(f_s\)。同样根号分治,若 \(|S|\le k\),枚举子集修改 \(f_s\)。否则,直接枚举超集贡献即可。

P10769 「CROI · R2」公交接驳

还不错的题目,感觉有点联赛风格。

首先我们直观地猜测,每个公交车应该刚好对应一段换乘站区间。因此我们可以设 \(f_{i,j}\) 表示前 \(i\) 个换乘站,用了 \(j\) 辆车的最小代价。转移即\(f_{k,j-1}+val(k+1,i)\to f_{i,j}\)。那么 \(val(i,j)\) 如何计算?首先就要确定出发点和出发时刻,显然应该到 \(i\) 的时刻应该是 \(t_i\),但不一定要在 \(t_i\) 的时候在 \(i\) 出发。可以在前面某个 \(v\) 小的地方出发也满足条件,所以直接取前缀 \(\min\) 即可。

然后可以继续猜测具有决策单调性。套个分治就搞定了。

P10538 [APIO2024] 星际列车

死去的 APIO。

首先这题要跳脱固有思维,不能一直对着点去想。应该可以感觉到,「时间」这个维度在这道题才是最关键的东西,因为时间是递增的,这样就方便我们 DP。

而和时间关联紧密的不是点而是边,于是把每条边拿出来 DP。设 \(f_i\) 表示走完第 \(i\) 条边的最小花费,则 \(f_i=\min\limits_{Y_j=X_i,B_j\le A_i} f_j+T_{X_i}c(B_j,A_i)+C_i\),其中 \(c(l,r)\) 表示在 \((l,r)\) 时间段内饭的数量。

将边按照时间排序,这样就有一个 \(\mathcal{O}(m^2)\) 的 DP 了。然后我们再次猜测具有决策单调性,于是写个二分队列就好了。

具体的,需要拿优先队列在每个 \(X_i\) 存储 \(B_j\),还需使用主席树维护 \(c(l,r)\)

反思:DP 的时候要想清楚维度,使得转移具有顺序。用边代替点去 DP 也是一种常见的切入角度。

posted @ 2024-11-29 08:04  xishanmeigao  阅读(56)  评论(0)    收藏  举报