Loading

2025赛季做题记录-other

图论/树论

DFN序

对于单点加\(w\),其子树中每个点到根的距离都加\(+w\),转化成\(\mathrm{dfs}\)序上一段区间的加,可以用树状数组维护

对于子树加\(w\),其子树中每个点都加上\((dep_y-dep_x+1)w=(1-dep_x)w+dep_yw\),开两个树状数组维护

对于查询,先用\(O(n\log n)-O(1)\)\(\mathrm{LCA}\),然后差分一下求距离即可。

因此总时间复杂度可以做到\(O(n\log n)\)


P5290 [十二省联考 2019] 春节十二响

既然祖先-后代关系不能放到同一个块,那么考虑自下而上处理,每次贪心地将子树中可以合并的合并,不难发现可以维护大根堆,子树合并时取出堆顶取\(\max\)合并


P6845 [CEOI 2019] Dynamic Diameter

直径有三种分析方向:

  1. 两次dfs。对于此题明显不适用。
  2. dp求。因为要动态维护,所以也不好处理。
  3. 暴力表示出来。虽然看着很劣但是在维护时可以优化,所以此题选用这个方法。

考虑直径的本质,就是距离最大的两个点:

\[\max_{x,y} \set{dis(x,y)} \\ =\max_{x,y}\set{d_x+d_y-2d_{lca(x,y)}} \]

这个\(lca(x,y)\)很难处理,但是在\(lca\)\(O(1)\)欧拉序求法中,我们可以用【 区间\([\min(L_x,L_y),\max(R_x,R_y)]\)中深度最浅的点 】来表示\(x,y\)\(lca\),其中\(L,R\)表示这个点在欧拉序中前后分别出现的位置。

所以原来的式子可以转化成:

\[\max_{x,y}\set{d_x+d_y-2\times \min_{u\in[\min(L_x,L_y),\max(R_x,R_y)]}d_u} \]

考虑在欧拉序上枚举两个点,那么原式就变成:

\[\max_{i\le j} \set{d^{\prime}_i+d^{\prime}_j-2\min_{i\le k\le j}d^{\prime}_k} \]

这个可以用线段树维护,考虑将左右两段拼起来,分最小值在左边、右边讨论即可。

而边的修改可以看做是子树\(d\)整体加,那么在欧拉序上体现为区间加,打\(\mathrm{tag}\)实现。


P5666 [CSP-S2019] 树的重心

枚举割哪条边然后求重心不好处理,考虑拆贡献,具体的,我们考虑每个点会在哪些边被割掉时作为重心。

原式中有两部分,其中子树外的部分很难处理,但是重心有性质:【如果我们以重心为根\(rt\),那么一个不是根的点成为重心所割掉的边一定不在其子树内】。可以考虑反证,因为割掉之后往子树里走显然是不优的。

先考虑\(x\ne rt\)。假设把树割掉了\(S\)(即\(x\)不在的部分的大小):

CSP-S2019-center.png

\(g_x=\max_{v\in son(x)}\set{sz_v}\),则满足割掉的边不在其子树内的点\(x\)可以作为重心等价于:

\[\left\{\begin{matrix} 2g_x\le n-S \\ 2sz_x\ge n-S \end{matrix}\right. \\ \Rightarrow n-2sz_x\le S\le n-2g_x \]

所以我们要对每个\(x\)统计有多少个不在其子树内的\(S\)在指定区间内。可以先全局统计,然后再减去子树内的。注意\(S\)的取值有\(sz\)\(n-sz\)两种情况,树状数组维护。

然后对于\(x=rt\),不难发现其能保留在重心的位置,当且仅当割掉一个子树后,根的每个儿子大小都满足要求。设\(rt\)的重儿子为\(u\),次重儿子为\(v\)

如果割掉的子树在\(u\)的子树中,那么\(u\)肯定满足条件,此时判断次重儿子\(v\)是否满足条件,即

\[2sz_v\le n-S \\ \Rightarrow S\le n-2sz_v \]

如果割掉的不在\(u\)子树内,那么判断\(u\)是否满足条件

\[2sz_u\le n-S \\ \Rightarrow S\le n-2sz_u \]

同样可以简单求。


P6118 [JOI 2019 Final] 独特的城市 / Unique Cities

题解


P7215 [JOISC 2020] 首都

归类:点分治

先考虑暴力怎么做。枚举最终首都的颜色,随便找一个点作为根 \(rt\),尝试将所有颜色相同的点都与 \(rt\) 连通。考虑开一个队列,表示当前要与 \(rt\) 连通的点,取出队头,尝试更新其父亲来连通,如果其父亲的颜色已经被合并,那么直接将其父亲入队,否则需要打通这个颜色,将所有这个颜色的点都入队即可。

由于要不断更换根,考虑点分治。一个看似错误的做法是每次以分治中心作为根,将其子树中的点并上来。但这样分治中心外的同色点就没办法被统计到。但我们发现此时可以直接舍弃这个分治中心,因为在更高层的分治层被扩展到的点肯定不会比当前分治中心为根扩展到的点多,所以以当前点为根是不优的,直接跳过。时间复杂度 \(O(n\log n)\)


CF840E In a Trap

归类:树分块

\(\max\set{a_i\oplus \mathrm{dist}(i,v)}\) 这样的式子常规数据结构不好维护,并且注意到数据范围 \(n\le 5\times 10^4\),那么直接考虑暴力分块。由于涉及到路径长度和异或,我们将 \(u\to v\) 这条链每 \(2^8=256\) 个点分一个块,从下到上从 \(0\) 开始编号,第 \(i\) 块涉及到 \([256i,256(i+1)-1]\) 级祖先。

回到原问题,我们考虑一条从 \(x\) 向上的链的第 \(i\) 块,记这一块的底部点,即 \(x\) 的第 \(256i\) 级祖先为 \(u\),那么考虑令 \(f_{u,i}\) 表示这一段的答案,可以表示出 \(f_{u,i}=\displaystyle\max_{j=0}^{255}\set{a_{\mathrm{fa}_{u,j}} \oplus (256i+j)}\)。由于在 \(2^8\) 意义下进行分块,我们将每个数拆成高8位和低8位,令 \(high_i=(a_i\texttt{>>}8),low_i=(a_i\& 255)\),则 \(a_i=256high_i+low_i\)

原式可以分开计算:

\[f_{u,i}=\displaystyle\max_{j=0}^{255}\set{256(high_{\mathrm{fa}_{u,j}}\oplus i)+low_{\mathrm{fa}_{u,j}}\oplus j} \]

考虑如何对于 \(u\) 快速求出所有 \(f_{u,i}\)。观察这个 \(\max\),对于每个 \(i\) 我们相当于要在 \((high_{\mathrm{fa}_{u,j}}\oplus i)\) 取到最大时 \((low_{\mathrm{fa}_{u,j}}\oplus j)\) 取到最大,可以将所有 \(high_{\mathrm{fa}_{u,j}}\) 挂到 \(\texttt{01-Trie}\) 上,即可查询到使得 \((x\oplus i)\) 的最大 \(x\),然后再对所有 \(high_{\mathrm{fa}_{u,j}}=x\)\(j\) 找到最大的 \((low_{\mathrm{fa}_{u,j}}\oplus j)\) 即可,可以开一个桶维护。由于 \(i\) 只有 \(O(\sqrt{n})\) 级别,\(\texttt{01-Trie}\) 上的查询是 \(O(\log n)\),所以可以 \(O(n\sqrt{n}\log n)\) 处理出所有的 \(f_{u,i}\)

查询时,只需要一块一块往上跳,时间复杂度 \(O(m\sqrt{n})\)。总时间复杂度 \(O(n\sqrt{n}\log n+m\sqrt{n})\),可以通过。


P12195 [NOISG 2025 Prelim] Itinerary

题解


CF827F Dirty Arkady's Kitchen

题解


CF1637F Towers

归类:贪心、构造

一般的路径覆盖很难刻画,不过观察到此题有重要性质:【所有塔一定是建在叶子(度数为 \(1\))节点上】。否则可以将每个塔调整到叶子,覆盖到的点不减反增,一定是不劣的。然后考虑一个点可以被怎样的两个塔约束,可以发现,要么是一点在子树内,一点在子树外,要么是两点都在子树内。不过在子树外的部分很难处理,此处用到一个很巧妙的技巧,类比点分治的思想,【把根钦定在 \(h\) 最大的点处】。于是为了满足根的要求,肯定是选择了两个不同的子树中的叶子,将其拼接,那么对于其他的任何子树,都至少存在一个子树外的点满足要求:

CF1637F.png

因此只需要对根考虑拼接两个子树,对其他的子树选出一条链调整即可,简单实现。


[AGC023F] 01 on Tree

归类:贪心

注意到原来的限制就是要求按照拓扑序,对于每个点,可以看作是要在其每棵儿子子树放好之后合并上来。那么考虑这样一种思路,每次选一个放在前面最优的子树(连通块)出来,计算其贡献后,将其合并到其父亲的连通块中。如何找到放到前面最优的连通块?考虑贪心,具体而言是 \(\texttt{Exchange Argument}\) 的方法,考虑两个连通块的情况,第一个分别有 \(a_{1},b_{1}\)\(0,1\),第二个有 \(a_2,b_2\) 个。那么第一个放在前面的贡献就是 \(b_1a_2\),第二个放在前面的贡献就是 \(b_2a_1\),因此第一个更优就等价于 \(b_1a_2<b_2a_1\),可以推广到多个个体的情况。因此可以维护一个堆,每次从中取出最优的连通块,将其合并到父亲。时间复杂度 \(O(n\log n)\)


P3206 [HNOI2010] 城市建设(动态MST)

这是动态 \(\mathrm{MST}\) 的板子。

考虑 \(\texttt{CDQ}\) 分治,对修改操作分治,\(\mathrm{solve}(l,r)\) 表示处理操作编号在 \([l,r]\) 中的修改操作,先做左边再做右边,递归到单点 \(l=r\) 时,需要对这个操作求出答案,然后打上修改。但是单点处需要快速求出修改一条边后的 \(\mathrm{MST}\) 状物,而这并不是容易的,如果保留边集为 \(m\),则我们求 \(\mathrm{MST}\) 就要 \(O(m\log n)\),因此我们需要利用上分治的结构,看看能不能将每个区间 \([l,r]\) 处保留下来的边集缩小到 \(O(r-l)\) 级别。

事实上这是可以的,我们可以对到达当前层的边进行缩减,剔出一些一定没有用的信息,我们称 \([l,r]\) 中修改操作涉及到的边集为动态边,其他为静态边,则我们需要简化静态边集:

  • 一定会在最终 \(\mathrm{MST}\) 中的静态边

    这些边我们可以先找出来,然后在并查集上合并,同时提前加上贡献。
    我们发现这些边的作用就是保证图最终可以连通,因此可以先将动态边的边权全部改成 \(-\infty\),然后跑一遍 \(\mathrm{MST}\),则仍然在 \(\mathrm{MST}\) 中的静态边就是一定要留下来的。

  • 一定不在最终 \(\mathrm{MST}\) 中的静态边

    这些边可以找出来之后直接抛弃掉。

    可以看做这些边被留下来的静态边偏序掉了,则可以将静态边找出来跑一遍 \(\mathrm{MST}\),则不在这个 \(\mathrm{MST}\) 中的边就是一定没有用的,其实这就是今年S组T2的重要结论。

可以证明,提前处理掉这些边之后,本层的静态边只有 \(O(r-l)\) 个,因为缩有用的静态边保证了合并并查集之后点数是 \(O(r-l)\) 级别的,而删无用边保证了边和点同阶。

因此可以每次剔出这些边之后往下走,使用可撤销并查集即可简单实现。时间复杂度 \(O(Q\log ^2 m)\)


数据结构

CF1491H Yuezheng Ling and Dynamic Tree

归类:分块

\(\mathrm{lca}\) 如何刻画?想到在树上倍增跳 \(\mathrm{lca}\) 的时候,是先将两个点调到同一高度,然后再同时往上跳到同一个点,于是类比 弹飞绵羊,我们将 \(a\) 数组分块,记块长为 \(B=\sqrt{n}\),用 \(to_i\) 表示点 \(i\) 往前跳跳出所在块到达的点编号。

\(\mathrm{lca}\) 时,若两点将要跳到的点编号不等,即 \(to\) 不相等,那么就不断将 \(to\) 大的用 \(u\leftarrow to_u\) 跳上来,调到相等后,如果两点不一样就把编号大的用 \(u\leftarrow a_u\) 跳父亲,这样两次复杂度都是 \(O(\sqrt{n})\) 的,因此可以做到 \(O(\sqrt{n})\) 单次处理询问。

考虑区间修改怎么做,对于散块,可以暴力修改然后重构。整块看似只能暴力修改然后重构,不好处理。但是我们挖掘一下 \(to_i\) 的性质,如果 \(a_i\le i-B\) 会发生什么,此时发现 \(i\) 的父亲肯定已经跳出了 \(i\) 所在的块,那么此时 \(to_i=a_i\) 恒成立。由于开始时有 \(a_i<i\),因此可以得到每个 \(to_i\) 只会在前 \(B\) 次操作中才可能被“改变”,在超过 \(B\) 次操作后一定有 \(to_i=a_i\)

所以每个块我们只需要暴力重构 \(B\),总共 \(\sqrt{n}\) 个块,每个操作 \(\sqrt{n}\) 次,每次操作重构复杂度 \(O(\sqrt{n})\),因此整块修改 \(to_i\) 的总复杂度就是 \(O(n\sqrt{n})\) 的。而对于 \(a_i\) 的修改,可以打 \(\mathrm{tag}\) 简单实现。

于是我们就在 \(O(n\sqrt{n})\) 的时间复杂度内解决了此题。

CF1523G Try Booking

归类:分治、树套树

考虑一个优雅的暴力,定义 \(\mathrm{solve}(l,r)\) 表示时间区间 \([l,r]\) 中会分配到的人数,那么根据分配方式,会选择编号最小的请求 \([L,R]\),然后递归到两边 \(\mathrm{solve}(l,L-1)\)\(\mathrm{solve}(R+1,r)\)。对于给定的长度限制 \(x\),由于每次至少减少 \(x\) 的长度,所以这个分治算法的复杂度是 \(O\left(\frac{n}{x}\right)\) 的。如果我们对于每个 \(x\) 做一遍,就是 \(\displaystyle\sum_{i=1}^{n}\frac{n}{i}=O(n\ln n)\),因此如果我们能快速找到 【满足 \(R-L+1\ge x,[L,R]\subseteq [l,r]\) 的编号最小的 \([L,R]\)】,那么就可以 \(\mathrm{poly\log}\) 解决问题。

先按区间长度扫描线,于是需要支持插入区间、查询区间。我们采用尽量简化修改的思路,对于查询 \([l,r]\),相当于要询问 \(R\le r\)\(L\ge l\) 信息;对于插入 \([L,R]\),其相当于要在 \(R\) 处更新 \(L\) 的信息。这样,我们就可以用树状数组套动态开点线段树解决,插入查询都是 \(O(\log^2 n)\),因此总时间复杂度 \(O(n\ln n\log^2 n+m\log^2 n)\),由于 \(n\le 5\times 10^4\)\(\log^3\) 的算法可以通过。

P11536 [NOISG 2023 Finals] Curtains

归类:扫描线、线段树

为了尽可能覆盖,原问题相当于判断所有 \(L\le l_i\le r_i\le R\) 能不能完全覆盖 \([L,R]\)。注意到这等价于 \(\forall x\in [L,R]\) 都有被区间覆盖到。先按照 \(R\) 扫描线,满足 \(r_i\le R\)。考虑扫描线时对于每个 \(x\) 维护 \(p_x\) 表示目前能够覆盖 \(x\) 的最大 \(l_i\)(限制最弱),那么如果满足 \(L\le p_x\) 那么 \(x\) 就可以被覆盖,因此对于所有 \(x\),条件为 \(L\le \displaystyle\min_{x\in [L,R]} p_x\)。于是只需要支持区间取 \(\max\)、区间查询 \(\min\) 即可,线段树即可解决。


QOJ.4420 Range Reachability Query

归类:bitset、分块

这个问题不弱于 \(\mathrm{DAG}\) 可达性问题,即 \([l,r]=[1,m]\) 的情况,可以用 bitset 做到 \(O\left(\frac{n^2}{\omega}\right)\)

那如果有编号限制,直接每次暴力跑可达性统计的复杂度连普通暴力都不如,分析到这个策略的主要问题是我们只需要查询 \(q\) 个点对的可达关系,而每次这样可达性统计就搞出 \(O(n^2)\) 个点对。

考虑并行处理询问,在每个询问的末节点处挂上这个询问,具体的,开 \(n\)\(q\) 位的 bitset,第 \(i\)bitset \(f_i\) 表示从点 \(i\) 出发,目前到每个询问末节点的可达性,即 \(f_{i}(j)=1\) 表示点 \(i\) 可以走到第 \(j\) 个询问的末节点。用 \(E_{(u,v)}\) 表示使边 \((u,v)\) 合法的询问集合,那么转移类似 \(f_{u}\leftarrow f_u\cup (f_v\cap E_{(u,v)})\),这样相当于将 \(q\) 个独立的询问放在一起,用 \(O\left(\frac{q}{\omega}\right)\) 的复杂度并行处理。考虑如何求出 \(E_{(u,v)}\),边映射到编号,本质是一个在编号上的下标,每个询问限制的编号区间是 \([l,r]\),因此异或差分一下即可快速求出 \(E\),然后按照拓扑序更新每条边 \((u,v)\),即可 \(O\left(\frac{mq}{\omega}\right)\) 求出所有 \(f\),那么对于每个询问,直接判 \(f_s(i)=1\) 即可,即从起点 \(s\) 可以走到当前询问的节点,也即两点联通。

于是似乎做完了,得到了正确的时间复杂度。但是空间 \(O\left(\frac{nq}{\omega}\right)\)似乎炸了,此处有 \(\texttt{trick}\),对询问分块,每 \(\omega=64\) 个分一段,于是每一段中的 bitset 就是一个 ull 能压进的状态,每次位运算直接变成 \(O(1)\),所以总时间复杂度还是 \(O\left(\frac{mq}{\omega}\right)\),空间优化到了 \(O(n)\)


P11803 【MX-X9-T7】『GROI-R3』此花绽放之时

题解


贪心

P11820 [PA 2015] 健身房 / Siłownia

归类:贪心

先放松限制,一步步来看.

如果 \(p_i\) 互不相同,那么就是一个区间选点的典中典贪心,策略就是按 \(r\) 排序从前往后扫,如果一个区间没有覆盖就选择其右端点,容易用夹逼法证明。

但是如果有 \(p_i\) 相同、不能选相同位置的限制,就可以出现以下问题:

P11820-samep_i_.png

此时右端点就只能贡献到一个黑色区间。那么选择哪个最优?注意到在我们的选择方式下,被选择的点是从前往后的,因此右端点越靠后的,越有机会会被后面的端点满足,所以此时选择右端点最靠左的是最优的。

但是如果出现右端点相同的怎么办?即如果有 \(p_i=p_j\wedge r_i=r_j\) 的区间,那么原来按照右端点最左选就无法区分区间的优劣。不妨设 \(l_i\le l_j\),此时我们发现能贡献到 \(i\) 的比能贡献到 \(j\) 的点要多,因此优先让限制小的 \(j\) 选择这个位置,而对 \(i\) 而言不能再选 \(r_i\) 了,因此 \(r_i\leftarrow r_i-1\) 即可。处理完这种情况,就是原来的贪心了。

关于贪心的实现,可以考虑对时间 \(t\) 扫描线,动态加入区间,时间复杂度 \(O(n\log n)\)


字符串

CF587F Duff is Mad

归类:\(\texttt{ACAM}\)、均摊

考虑 \(\texttt{ACAM}\) 是如何处理一堆串在一个串中的出现次数的问题。做法是对匹配串的每一个节点跳 \(\mathrm{fail}\) 树,跳到的文本串尾节点的个数和。为了将统计放在匹配串上,可以看做将每个匹配串尾节点的子树(\(\mathrm{fail}_i\to i\))打标记,求匹配串每个节点的标记个数和。

\(l,r,k\) 的询问可以拆成前缀和形式,于是只需要处理 \(1,r,k\),即某个前缀对某个特定串的贡献。传统的 \(\texttt{ACAM}\) 算法显然不能解决这类问题了,考虑均摊,令 \(m=\displaystyle\sum_{i=1}^{n}|S_i|\),设定阈值 \(B\)

  • \(|S_k|>B\)

    这样的 \(S_k\) 只有 \(O\left(\frac{m}{B}\right)\) 个,考虑对每个这样的 \(S_k\) 线性处理所有 \(r\) 的答案,将 \(S_k\) 上的所有节点打上标记,扫到 \(S_r\) 则算上其尾节点子树内的贡献,这部分可以做到 \(O\left(\frac{m^2}{B}\right)\)

  • \(|S_k|\le B\)

    这意味着 \(S_k\) 跑一遍统计是 \(O(B)\),考虑对 \(r\) 做扫描线,每扫到一个 \(S_r\) 就将其尾节点的子树加上贡献,将挂在 \(r\) 上的每一个 \(S_k\) 暴力遍历每一个节点,统计其贡献和。于是需要支持子树加、单点查,子树加拍到 \(\mathrm{dfn}\) 序上就是区间加,考虑 \(O(\sqrt{m})\) 修改,\(O(1)\) 查询的分块,这样加需要 \(O(n\sqrt{m})\),查询需要 \(O(qB)\),总和起来就是 \(O(n\sqrt{m}+qB)\)

均值不等式一下,解得 \(B=\cfrac{m}{\sqrt{q}}\),总时间复杂度为 \(O(n\sqrt{m}+m\sqrt{q})\),非常厉害。


P3546 [POI 2012] PRE-Prefixuffix

分类:\(\texttt{border}\)、性质

很容易发现 \(\texttt{AB,BA}\) 形式的循环同构在原串中体现为求 \(\texttt{border}\) 然后再在剩下的部分再求一次最大 \(\texttt{border}\)。用 \(f_i\) 表示原串头尾掐掉 \(i\) 个字符后,即 \(s[i+1,n-i]\) 的最大 \(\texttt{border}\) 长度。那么答案可以表示为 \(\displaystyle\max_{i\texttt{ is border}}\set{i+f_i}\)。于是问题变成如何快速求出所有 \(f_i\)

一个一个单次求显然很难快速处理,考虑递推,考察 \(f_i,f_{i+1}\) 之间的关系:

其中绿色是 \(f_i\) 表示的最大 \(\texttt{border}\),不难发现,去掉红色蓝色两个相等字符后,黄色部分是相等的,也即黄色部分可以作为 \(f_{i+1}\)\(\texttt{border}\),其长度为 \(f_i-2\),于是我们得到重要性质:\(f_{i+1}\ge f_i-2\)

那么问题就变得简单了,\(i\) 从大到小扫,每次 \(f_{i}\) 都有上界 \(f_{i+1}+2\),从这个上界开始暴力求出满足要求的最大 \(\texttt{border}\),可以用字符串哈希 \(O(1)\) 判断,分析一下发现总共只需要 \(O(n)\) 次判断,时间复杂度 \(O(n)\)


构造

P8866 [NOIP2022] 喵了个喵

先考虑 \(k=2n-2=2(n-1)\) 怎么做。这启发我们使用 \((n-1)\) 个栈放卡片,每个栈最多放两个,然后再空一个栈。这样,每当一个卡牌进来,如果前 \((n-1)\) 个栈栈顶有相同颜色的,那么直接放上去就消掉了,否则如果某个栈底有颜色相同的,那么放到空栈里操作栈底也能消掉。

对于 \(k=2n-1\),比 \(k=2n-2\) 多了 \((2n-1)\) 这种颜色的牌。在此情况下,可能出现当前的牌不能立刻消掉的情况。

假设当前牌堆顶的牌 \(x\) 没有办法安置,我们转换思路,考虑找到后面的一个牌 \(y\),使得 \(y\) 在当前的栈底出现过,然后将 \(x\) 放到对应栈栈顶,这样轮到 \(y\) 放的时候,可以通过底部消除,把 \(x\) 这个栈消到符合要求:

但是这个策略并不是对于所有情况都可行,\(x\) 放到栈上面,会堵住原来的栈顶,使得原本能消除掉的牌无法消除,堵在上面:

如何解决?我们考虑\(x\) 放到空栈里

但是不难发现,此时原先要消掉栈底的那个栈一定会变成空的,所以我们转变空栈,那就顺利完成了消除。

于是,我们对于所有情况都有了应对方案,可以构造:

\(x\) 表示当前没有办法安置的卡牌,\(y\) 表示后面在栈底出现的牌,用 \(P\) 表示 \(y\) 所在的栈,\(z\) 表示 \(P\) 的栈顶。

  • 当后面的 \(z\) 放到 \(P\) 处没有剩余,即 \(z\) 的个数是偶数时

    此时可以将 \(x\) 放到 \(P\) 的栈顶,后面的 \(z\) 会在栈顶消完,最后用 \(y\) 消掉 \(P\) 的栈底。

  • 当后面的 \(z\) 放到 \(P\) 处有剩余,即 \(z\) 的个数是奇数时

    此时可以将 \(x\) 放到空栈,此时后面的牌一定可以将 \(P\) 变空,将 \(P\) 变成新的空栈即可。

注意特殊情况,如果 \(x\) 后面有另一个 \(x\)\(y\) 之前,那么可以将 \(x\) 放到空栈里,一直消到下一个 \(x\)


P6892 [ICPC 2014 WF] Baggage

观察样例,我们猜测操作次数最少就是 \(n\) 次,且我们只会用到两个空位。

考虑边界,\(n=1,2\) 都是无解的,\(n=3\) 不止需要两个空位,\(n=4\) 在只用两个空位的情况下可行,以此为突破:

初始状态:

__BABA[BABA...BABA]BABA

目标状态:

AAAA[AAAA...BBBB]BBBB__

考虑操作:

__BA[BABA...BABA]BABA
ABBA[BABA...BABA]B__A
ABBA[__BA...BABA]BBAA

我们发现里面是一个子问题,如果可以递归解决,那么:

ABBA[AAAA...BB__]BBAA

不难发现,可以:

ABBA[AAAA...BB__]BBAA
A__A[AAAA...BBBB]BBAA
AAAA[AAAA...BBBB]BB__

所以 \(n=5,6,7\) 作为边界,每次递归到 \(n-4\),可以在 \(n\) 次操作完成。


【UNR #1】Jakarta Skyscrapers

以下令 \(a\le b\)

先考虑 \(a=1\) 怎么做,不难发现可以迭代:

\[b,1\Rightarrow b-1 \\ b-1,1\Rightarrow b-2 \\ b,b-2\Rightarrow 2 \\ b-2,2\Rightarrow b-4 \\ b,b-4\Rightarrow 4 \\ \dots \]

那么可以凑出所有 \(2^k\),用 \((b-c)\) 二进制拆分后依次减去幂次即可。可以做到大约 \(3\log_2 b\) 次操作。我们称之为【方法】。

对于其他情况,我们有性质:能凑出 \(c\),等价于 \(\gcd(a,b) \mid c\)。必要性:因为 \(a,b\) 每次减得到的数一定都是 \(\gcd(a,b)\) 的倍数。所以我们考虑先凑出 \(\gcd(a,b)\),然后用 \(\gcd(a,b)\) 凑出 \(c\),就有了充分性。

\(\gcd\) 考虑使用辗转相除,\(\gcd(x,y)=\gcd(y,x\bmod y)\),此处假设 \(x\ge y\),那么 \(x\bmod y\) 能通过类似 【方法】倍增凑出,然后递归,操作数看似是 \(\log^2\) 级别的,但是分解复杂度是 \(\sum \log\) 的,总和起来是 \(\log\) 级别的操作数。

在得到 \(\gcd(a,b)\) 后,我们可以用 \(a\)\(\gcd(a,b)\) 使用【方法】,得到 \(\gcd(a,b)\) 的幂次,凑出 \(c\)


CF2135D1

题解


ARC199A

非常 \(\texttt{AD-Hoc}\) 的一道题。重要突破口:\(R_i,C_i<\frac{N}{4}\)

由于行和列都会互相影响,所以从整体考虑会无从下手。不妨先将第 \(1\) 行通过一些列操作变成全部都是 \(0\) 的,这样之后的列操作次数就恰好是 \(R_1\),是一个定值。由于行列操作顺序无关紧要,认为先操作完行再操作列。此时每一行有怎样的性质?考虑第 \(i\) 行,其目前有 \(x\)\(1\),考察其在后面的 \(R_1\) 次列操作后 \(1\) 的个数,可以得到一个相当宽的上界 \(R_i\in [x-R_1,x+R_1]\),我们对 \(x\) 求出一个上界:由于 \(R_i<\frac{N}{4}\),所以 \(x-R_1<\frac{N}{4}\Rightarrow x<\frac{N}{4}+R_1\),又因为 \(R_1<\frac{N}{4}\),所以 \(\boxed{x<\frac{N}{2}}\)。也就是说,这一行想要在列操作后合法,起码需要满足 \(1\) 的个数 \(<\frac{N}{2}\)。那很明显了!

  • 如果 \(x<\frac{N}{2}\),此行一定不需要反转。

  • 如果 \(x>\frac{N}{2}\),此行一定需要反转。

  • 如果 \(x=\frac{N}{2}\),此行无论怎么搞都是寄的,无解。

搞出了每一行是否需要反转,问题就变得简单了,对于每一列再判断一下反转即可。


P9870 [NOIP2023] 双序列拓展

考察 \(\ell_0=10^{100}\) 的意义,这表明我们可以任意将 \(X,Y\) 对齐,而 \(\forall i,j, (f_i-g_i)(f_j-g_j)<0\) 的意义显然就是要么 \(\forall i,f_i<g_i\) 或是 \(\forall i,f_i>g_i\),只需要考虑前者,后者直接 \(\texttt{swap}\) 就是等价的。那么可以设计一个朴素的 \(\mathrm{dp}\)\(f_{i,j}\) 表示将 \(X_{[1\sim i]}\)\(Y_{[1\sim j]}\) 对齐是否可行,转移不难推出,就是继承 \(X_i\) 或继承 \(Y_i\) 或是两者都继承:

\[f_{i,j}=f_{i-1,j} \vee f_{i,j-1} \vee f_{i-1,j-1}\quad (X_i<Y_j) \]

直接制作单次是 \(O(nm)\) 的,无法接受。考虑从猎奇角度优化这个 \(\mathrm{dp}\)

不难将其看做网格上走路,每一步可以向右/下/右下走去,且只能走 \((i,j)\) 满足 \(X_i<Y_j\),问是否可以从 \((1,1)\) 走到 \((n,m)\)。这个直接想是很困难的,考虑从特殊性质入手,其保证 \(x_n=\min X,y_m=\max Y\),这提示我们考察序列的最值,考察最值所处的行列的性质。

我们发现,若 \(X_{\min}\ge Y_{\min}\),则有 \(\forall i,X_i\ge Y_{\min}\),因此 \(Y_{\min}\) 所处的这一列一定是全部都不可走的,这样会形成一条隔离线,一定走不通,同样的,若 \(X_{\max}\ge Y_{max}\) 那么 \(X_{\max}\) 这一行也是堵住的。

反之,若 \(X_{\min}<Y_{\min}\),则 \(X_{\min}\) 这一行一定都是被打通的,若 \(X_{\max}< Y_{\max}\),那么 \(Y_{\max}\) 所处列也一定是打通的,这个性质有什么用?在特殊性质中,这意味着第 \(n\) 行和第 \(m\) 列一定都是被打通的,所以如果我们可以走到第 \(n\) 行或者第 \(m\) 列则可以顺着这条通路走到 \((n,m)\)

P9870-leftside.png

这似乎形成了一个子问题的形式,用 \(\mathrm{check}(x,y)\) 表示从 \((1,1)\) 是否可以走到 \((x,*)\) 或是 \((*,y)\)。特殊性质就是询问 \(\mathrm{check}(n,m)\)。考虑再次找出左上角 \(X_{[1\sim n-1]}\)\(Y_{[1\sim m-1]}\) 的最值,同理此时若是 \(X_{\min}<Y_{\min}\),则 \(X_{\min}\) 这一行一定都是被打通的,我们发现这个判断的矩形(绿色边框)发生了收缩,可以递归到 \(\mathrm{check}(\min X,y)\) 去检查,同理若 \(X_{\max}<Y_{max}\),则收缩到 \(\mathrm{check}(x,\max Y)\),最后若是 \(x=1\vee y=1\) 就是成功了,否则是失败了。这样我们成功地将时间复杂度优化到了 \(O(n+m)\),可以接受。

接下来考虑正解就非常容易了,找到全局的 \(X,Y\) 最值,其形成的合法通道一定是一个十字状:

P9870-all.png

那么只需要左上角的可以走到这个十字上,右下角可以从十字走到 \((n,m)\) 就完成了,因此只需要对称的实现 \(\mathrm{checkl,checkr}\) 表示走左上角走右下角的合法性。时间复杂度 \(O(T(n+m))\),可以通过。


数论数学

除数函数求和

归类:线性筛

明显拆贡献,答案就是

\[\sum_{d=1}^{n}\left\lfloor\frac{n}{i}\right\rfloor i^k \]

可以枚举 \(i\),重点是如何快速求出所有 \(i^k\)。直接快速幂求是 \(O(n\log k)\) 的,无法接受。

考虑 \(i^k\) 性质,我们令 \(f(x)=x^k\),由于 \((ab)^k=a^kb^k\),所以有 \(f(ab)=f(a)f(b)\),因此 \(f\) 是一个积性函数,那么我们可以在跑筛的时候顺便处理出所有的 \(f(i)\),具体的,我们有 \(f(ip)=f(i)f(p)\)

因此总时间复杂度是 \(O\left(\frac{n\log k}{\ln n}+n\right)\),可以通过。


P6620 [省选联考 2020 A 卷] 组合数问题

归类:组合数、二项式定理

首先多项式在和式下可以拆成单项式逐个求解,即我们要求

\[a_i\times \boxed{\sum_{k=0}^{n}k^ix^k\binom{n}{k}} \]

\[\begin{gathered} 令 F(n,m)=\sum_{k=0}^{n}k^mx^k\binom{n}{k} \\ =\sum_{k=0}^{n}k^mx^k\left[\binom{n-1}{k}+\binom{n-1}{k-1}\right] \\ =\sum_{k=0}^{n}k^mx^k\binom{n-1}{k}+\sum_{k=0}^{n}k^mx^k\binom{n-1}{k-1} \\ \end{gathered} \]

Part 1:

\[\sum_{k=0}^{n}k^mx^k\binom{n-1}{k}=\boxed{F(n-1,m)} \\ \]

Part 2:

\[\begin{gathered} \frac{1}{n}\times k\times \binom{n}{k}=\binom{n-1}{k-1} \\ \sum_{k=0}^{n}k^mx^k\binom{n-1}{k-1}=\frac{1}{n}\sum_{k=0}^{n}k^{m+1}x^k\binom{n}{k}=\boxed{\frac{1}{n}F(n,m+1)} \\ \end{gathered} \]

综上,我们得到了

\[F(n,m)=F(n-1,m)+\frac{1}{n}F(n,m+1) \]

进行化简,考虑 \(F\)\(m-1\) 上的取值,即

\[\begin{gathered} F(n,m-1)=F(n-1,m-1)+\frac{1}{n}F(n,m) \\ \boxed{F(n,m)=n\left[F(n,m-1)-F(n-1,m-1)\right]} \end{gathered} \]

考虑边界,用二项式定理转化:

\[F(n,0)=\sum_{k=0}^{n}x^k\binom{n}{k}=(1+x)^{n} \]

最后我们要求的就是 \(F(N,*)\)

\(F\) 看似是 \(N\times M\) 的,但是不难发现 \(F(N,*)\) 的取值只与 \(n\ge N-M\) 的有关,所以 \(F\) 就是 \(M^2\) 级别的,可以直接递推计算。

时间复杂度 \(O(M^2)\)


P3518 [POI 2011] SEJ-Strongbox

归类:裴属定理、\(\gcd\)

先考虑只有一个数 \(a\),此时 \((ka)\bmod n\) 都能被表示,所以 \(x\) 能被表示等价于 \(x\equiv ka\pmod n\),这是一个线性同余方程的形式,根据裴蜀定理,\(x\) 能被表示,等价于 \(\gcd(a,n) \mid x\)

扩展这个过程,两个数 \(a,b\),则 \(x\mid \gcd(a,n)=k_1\)\(y\mid \gcd(b,n)=k_2\) 都能被表示,设 \(x=d_1k_1,y=d_2k_2\),则 \(z\equiv x+y\equiv d_1k_1+d_2k_2\pmod n\),这也是一个线性同余方程的形式,同理可得此时 \(\gcd(a,b,n)\mid z\)

归纳得到,\(k\) 个数 \(a_1,a_2,\dots a_k\),能表示出数 \(x\) \(\Leftrightarrow\) \(\gcd(a_1,a_2,\dots,a_k,n) \mid x\)

对应到此题,由于 \(m_k\) 已经固定为密码之一,所以我们相当于要找到一组 \(a_1,a_2,\dots a_{tot}\),令 \(d=\gcd(n,m_k,a_1,a_2,\dots a_{tot})\),此时能表示的数就是 \(d \mid x\) 的数,由于 \(m_{1\sim k-1}\) 都不是密码,所以 \(\forall i\in[1,k-1],d\nmid m_i\)

\(x=\gcd(n,m_k)\),我们可以枚举 \(g=\gcd(a_1,a_2,\dots,a_{tot})\),不难发现 \(g\mid x\),所以可以枚举 \(x\) 的因数作为 \(g\)。我们判断是否有 \(\forall i\in[1,k-1],g\nmid m_i\),如果满足,此时不同的 \(a\) 就有 \(\left\lfloor\frac{n}{g}\right\rfloor\) 个,将其取最大即可得到答案。

直接暴力判断,时间复杂度是 \(O(\sigma(x)\times k)\),无法接受。

考虑通过预处理优化判断的过程,我们要查询一个数是否是一堆数中某个的因数。首先,可以对于每个 \(m_i\)\(x\)\(\gcd\),显然不影响结果,因为 \(g\mid x\wedge g\mid m_i\Leftrightarrow g\mid \gcd(x,m_i)\)。然后,我们标记 \(m_i\) 的所有因数。直接枚举因数太慢,但是我们发现取 \(\gcd\) 后所有的 \(m_i\mid x\),因此可以先求出 \(x\) 的所有质因数,然后用质因数进行分解,即可快速标记所有因数。

在此方法下,本质不同的因数只有 \(O(\sigma(x))\) 个,加上记忆化打标记,总时间复杂度是 \(O(k\log x+\sqrt{x}+\sigma(x))\)


杂项

CF1774G Segment Covering

归类:区间问题、容斥、倍增

对于区间相关题目,考虑挖掘包含等性质来简化。对于此题,考虑两条包含的线段:\(A\subset B\),如果我们已经选择了 \(A\),那么 \(B\) 的选择对于整体的并集是没有影响的,并且此时选/不选 \(B\) 对于后续 \(f,g\) 的方案数贡献都是相同的,换言之,\(A\) 选择后对于 \((f-g)\) 一定没有贡献,所以相当于钦定 \(A\) 不选,因此 \(A\) 可以直接抛弃。所以我们只剩下了两两不包含的区间。注意到其性质是,排序后左端点、右端点都是严格单增的

考虑一个询问 \([l,r]\),假设被其包含的区间为: \([l=l_1,r_1],\dots [l_k,r_k=r],l_1< \dots <l_k,r_1< \dots < r_k\),首先 \([l_1,r_1]\) 是必选的,然后从前往后考虑每个区间,假设有区间 \([l_1,r_1],[l_2,r_2],[l_3,r_3]\)

---1---
 ----2----
        -----3-----

如上,为了保证连续,这三个区间都必须入选。

---1---
 ----2----
   -----3-----

如上,如果我们选择了 \([l_3,r_3]\),那么中间的 \([l_2,r_2]\subset [l_1,r_1]\cup [l_3,r_3]\),所以类比包含的思考过程,选 \([l_3,r_3]\)\((f-g)\) 是没有贡献的。并且由于要连续,\([l_2,r_2]\) 就是必选的,注意到最后这样选得的区间就是:

---1--- ---3---  --5--
  ---2--- ----4----

相当于钦定这些区间必选,记区间个数为 \(k\),那答案就是 \((-1)^k\)

具体实现时,先保留不包含其他区间的区间,对于询问,判断能不能构成并集恰好为 \([l,r]\) 的区间集,不能答案就是 \(0\)。对于有方案的情况,构造这些区间以求出区间个数,相当于上下选择两个初始的区间,每次都往后跳 \(l_j>r_i\) 的区间,直到覆盖完,可以倍增跳,跳完之后,若选到同一点或者最后没有跳到 \(r\),说明舍弃掉无用区间后没有方案,那么答案就是 \(0\),否则记录跳过的区间个数,答案就是 \((-1)^k\),可以 \(O(n\log n)\) 解决。


P12018 [NOISG 2025 Finals] 机器人

题解


CF1896D Ones and Twos

类人思维题。Instead of 思考有哪些和可以被得到,我们逆向思考,假设现在有一个和为 \(x\) 的区间 \([l,r]\),可以得到什么?\(a_i\) 只有 \(1,2\) 是很重要的,分讨一下 \((a_l,a_r)\) 的取值,我们发现:

  • \((1,1)\),将区间缩到 \([l+1,r-1]\),和变成 \(s-2\)
  • \((1,2)\),将区间缩成 \([l,r-1]\),和变成 \(s-2\)
  • \((2,1)\),将区间缩成 \([l+1,r]\),和变成 \(s-2\)
  • \((2,2)\),将区间缩成 \([l,r-1]\)\([l+1,r]\),和变成 \(s-2\)

这意味着,任意一个和为 \(s\) 的区间都可以得到和为 \(s-2\) 的区间。因此问题变成找到和 \(x\) 同奇偶的最大区间和 \(s\),询问是否有 \(s\ge x\),那么首先 \([1,n]\) 作为 \(\left(\sum a\right)\bmod 2\) 的选择,而与整体和异奇偶的可以找到左右两端最靠外的 \(1\),位置记为 \(p,q\),则 \([p+1,n],[1,q-1]\) 可以作为选择,取 \(\max\) 作为 \(s\) 即可。

于是可以用 set 维护 \(1\) 的位置,用树状数组维护区间和即可,时间复杂度 \(O( n \log n)\)


P11234 [CSP-S 2024] 擂台游戏

我们称能力值不确定的选手为[自由选手],[时刻 \(i\)] 表示 \(1\sim i\) 的选手信息确定是的情况 。

分析一下某位选手在某一轮中被打败的条件:

  1. 这个人是擂主,但是守擂失败。

  2. 这个人不是擂主,其 bro 子树中存在的唯一确定\(^{\dagger}\)的赢家选手能够守擂成功。

    \(\dagger\):要求唯一确定是因为,若有多个选手可能成为赢家,其中必定有自由选手,记当前轮次为 \(k\),我们可以钦定自由选手能力值选择 \(k-1\),其必然可以胜出,并在与当前选手的对决中输掉,这样当前选手就守擂成功了,因此 bro 子树中只能由唯一确定的赢家选手。

对于[1],如果该选手是自由选手,则此条件无效;否则该选手的能力值必须 \(\ge \max\),其中 \(\max\) 表示此人当擂主的轮次最大值。对于[2],考察子树中唯一胜者的性质,我们发现存在时刻 \(g_x\) 满足之后子树中能力值为 \(f_x\) 的选手都是该子树的唯一胜者,且一直维持。那么假设当前时刻为 \(t\),则 \(t\ge g_x\)\(x\) 子树就存在能力值为 \(f_x\) 的唯一赢家,若此时有 \(f_x\ge k\) 则其可以守擂成功,该选手就失败了。从两个条件的限制不难发现,对某个选手而言,可以使其胜出的时刻是一段前缀,那么我们可以找到这些区间用差分加上,即可一次性算出所有 \(c_i\) 的答案。

先求出 \(f,g\)。这个不难使用 \(\mathrm{dp}\) 解决,边界在叶子处,此时 \(f_u=a_u,g_u=u\)。考虑节点 \(u\) 处,若左子树的赢家 \(f_{lc}\) 作为擂主,如果 \(f_{lc}\ge k\) 则左子树可以守擂成功,故只能在左儿子的时刻中才能赢,此时 \(g_u=g_{lc}\),否则该点可以获得胜利,\(g_u=g_{rc}\)\(f\) 的转移很简单,取此轮中会赢的转移即可。

求出 \(f,g\) 后考虑怎么对每个选手求出符合要求的区间,一个一个选手往上跳求出区间是 \(O(n\log n)\) 的,无法接受,考虑一种类似标记永久化的思想:自顶向下下放所有限制,在叶子结点处就可以得到贡献区间,直接差分加上。所有 \(c_i\) 补全后的子树都是“极左”的,即从根节点开始一直走左儿子构成的所有子树,我们发现这些子树大小的和是 \(n+\frac{n}{2}+\frac{n}{4}+\dots=O(n)\) 的,因此我们可以对每一个这样的子树搜一遍计算。向子树内走时根据上述分析讨论一下即可。

因此总时间复杂度 \(O(Tn)\),非常牛。

posted @ 2025-08-21 15:09  STDJCY  阅读(40)  评论(0)    收藏  举报