9,10 月 NOIP 模拟赛总结

oiclass #9

T2 染色 II (状压dp,dp优化)

\(x,y\in S\) 则 \((x\operatorname{or} y)\in S\) 说明 \(S\) 对 \(\operatorname{or}\) 运算封闭。

从全集开始考虑。假设 \(2^n-1\) 是蓝色的,考虑找到 \(a\) 中所有的红色位置,记这些位置的或和为 \(S\),考察其具有的性质。注意到位置 \(S\) 一定是红色的,并且所有红色位置必定是 \(S\) 的子集,也就意味着其他位置一定只能是蓝色。这样整个全集就被劈成了两部分,其中外部已经确定了全部都是蓝色的,而内部变成了一个子问题。于是可以设计 \(\mathrm{dp}\)。

令 \(f_{S,0/1}\) 表示考虑 \(S\) 的子集,已经确定位置 \(S\) 的颜色为蓝色/红色的最小价值。\(0/1\) 是对称的,只考虑蓝色。

\(O(2^nn)\) 高维前缀和求出 \(sum_S\) 表示集合 \(S\) 内部的价值和。

\[f_{S,0}=\min_{T\subset S}\set{f_{T,1}+sum_S-sum_T} \]

时间复杂度 \(O(3^n)\),无法通过。考虑优化。

由于枚举子集,我们有 \(|T|<|S|\),我们不一次命中 \(T\),考虑每次只剥离掉一个元素,并在剥离的时候计算上贡献。一定可以找到一个 \(x\in S\) 使得 \(x\in S\wedge x\not\in T\)。令 \(S^\prime=S\setminus \set{x}\),则我们假设 \(T\subseteq S^\prime\)。考虑剥离掉这个 \(x\) 带来的贡献,容易发现就是包含 \(x\) 的那些集合,也就是 \(sum_S-sum_{S^\prime}\) 的贡献。考虑 \(T\) 位置的颜色,如果 \(T\) 正好就是我们想要转移到的那个子集,那么 \(T\) 就应该是红色,否则还没有剥离到最终的子集 \(T\) 就应该是蓝色,因此我们发现 \(T\) 作为蓝色红色都可以,那么转移就是:

\[f_{S,0}=\min_{x\in S}\set{\min(f_{S^\prime,0},f_{S^\prime,1})+sum_S-sum_{S^\prime}} \]

oiclass #10

T4 追忆(树结构,性质分析)

题意就是要求覆盖图中至少 \(i\) 个点所需的最少路径条数。

首先我们选择的路径端点一定都是叶子,否则可以将其扩展到叶子使得覆盖点更多。

考虑 \(i=n\) 的情况。我们熟知,假设树中有 \(l\) 个叶子,那么覆盖所需的最少路径条数为 \(\lceil\frac{l}{2}\rceil\)。

假设我们选择了 \(2l\) 个叶子,考察这些叶子配对之后的 \(l\) 条路径能够覆盖的最多点数。

从叶子出发对整棵树进行拓扑排序,这样可以将树从下到上切开:

对每一层,考虑最底下的 \(2l\) 个叶子能够覆盖这一层的多少点。不难发现,每个点都可以从子树中挑一个叶子出来进行匹配,因此每层都可以覆盖到 \(2l\) 个点。但是这层可能没有那么多点给它覆盖,假设这层有 \(cnt\) 个点,那么能覆盖到的点就是 \(\min(2l,cnt)\)。

因此 \(2l\) 个叶子能够覆盖的最多点数就是 \(S=\sum\limits_{i}\min(2l,cnt_i)\)。对 \(cnt_i\) 排序后扫即可。

时间复杂度 \(O(n\log n)\),使用桶排即可做到 \(O(n)\)。

oiclass #11

T3 奶龙网络(dp,分块)

我们会 \(O(2^knm)\) 的状压做法,这个做法能在 \(k\) 较小时猛猛通过。

有一个类似 meet-in-the-middle 的想法,就是前 \(n-k\) 个暴力枚举状态,后 \(k\) 个用 \(\mathrm{dp}\) 合并,可以做到 \(O(2^\frac{n}{2} \mathrm{poly}(n))\)。受其启发,考虑按 \(k\) 定长分块。马靴说的道理:定长分块可以看成网格图。

在 \(k>16\) 时 \(\lceil n/k\rceil\le 3\),这个网格图最多只有 \(3\) 行。

按列从左到右扫,考虑新增格子 \((r,c)\) 的贡献,发现只有同一行前面的 \(1\)(蓝色)以及下一行前面的 \(1\) 往后的贡献(绿色)。设 \(w_r\) 表示只考虑当前列之前的位置,第 \(r\) 行 \(1\) 的个数和。因此新增贡献是 \(w_r+[r<R]w_{r+1}\)。这样可以设计 \(\mathrm{dp}\),把 \(w_1,w_2,w_3\) 放进状态里,即 \(f(c,w_1,w_2,w_3,s)\) 表示考虑前 \(c\) 列,三行的和分别为 \(w_1,w_2,w_3\),且对数和为 \(s\) 的方案树。时间复杂度 \(O(k^{n/k}km)\)。

oiclass #12

T2 下取整(性质分析,dp 优化)

先按 \(a\) 升序排序。贡献是环状的,不好处理。考虑从最大值 \(a_n\) 的位置断开环,从 \(a_n\) 后面的位置开始走,这样可以直接消除掉 \(\lfloor\frac{B_1}{B_n}\rfloor\)。这样操作一定不劣,因此最优解中 \(B_n=a_n\),断环成链。

类比找到 \(a_1\) 的位置,可以发现 \(a_1\) 之前一定是递减的。现在只考虑 \(a_1\to a_n\) 的部分。容易发现这部分一定是递增的,否则可以把凹下去的部分扔到左边拼起来。现在唯一能造成贡献的就是 \(a_1\sim a_n\) 递增部分带来的贡献。

直接设计 \(\mathrm{dp}\) 令 \(f_i\) 表示以 \(a_i\) 结尾的贡献最小值。不难得到转移:\(f_i=\min\limits_{j<i} \set{f_j+\lfloor\frac{A_i}{A_j}\rfloor}\)。

有一万种方法优化,比较简单的就是先去掉下取整,转化成 \(\lfloor f_j+\frac{A_i}{A_j}\rfloor\),然后斜率优化就行了。

T4 救护车(背包 dp,贪心)

有点过于神秘了。

先令 \(T\leftarrow \lfloor\frac{T}{2}\rfloor\)。问题可以被转化成:有 \(4\) 个容量为 \(T\) 的背包,要把 \(n\) 个物品放进去,每个物品放到不同背包中贡献不同的重量,问能不能做到。于是就可以设计一个 \(O(nT^4)\) 的可行性背包,可以进一步将状态设计为前三个背包已用容量固定时第四个背包已用容量的最小值,从而做到 \(O(nT^3)\),直接优化比较困难。

考虑弱化问题,弱化成只有两个对角的医院,以 \((1,1)(L,L)\) 为例,对于位置 \((x_i,y_i)\):

  • 放到 \((1,1)\) 的代价是 \(a_i=(x_i+y_i-2)\)。
  • 放到 \((L,L)\) 的代价是 \(b_i=(2L-x_i-y_i)\)。

可以发现对于同一个点,其到两个医院的代价之和 \(a_i+b_i=2(L-1)\) 为一个定值,这意味着 \(a_i\) 越大 \(b_i\) 越小,因此按照 \(a_i\),也就是 \((x_i+y_i)\) 升序排序后,最优解一定是一段前缀给 \((1,1)\),后缀给 \((L,L)\)。对 \((1,L)(L,1)\) 也是同理,按 \((x_i-y_i)\) 升序排序后一定是一段前缀给 \((1,L)\) 一段后缀给 \((L,1)\)。于是弱化的问题得到了解决,现在考虑拓展到 \(4\) 个角。

我们注意到 \(2\) 个对角的结论可以扩展到 \(4\) 个角,对 \((1,1)(L,L)\) 而言,就是按照 \((x_i+y_i)\) 排序后,一定存在分界点 \(p\) 使得 \(p\) 之前的点全部选择 \((1,1)\),后面的点全部选择 \((L,L)\),同理按 \((x_i-y_i)\) 排序后一定存在 \(q\) 使得 \(q\) 之前全部选择 \((1,L)\),之后全部选择 \((L,1)\)。

考虑直接枚举分界点 \(p,q\),这样可以把所有点分成四类:按 \((x_i+y_i)\) 排序后在 \(p\) 左边还是右边;按 \((x_i-y_i)\) 排序后在 \(q\) 左边还是右边。这样每一类内部的点只有两个医院可以选。于是就可以用之前的 dp 了,对于每一类,令 \(f_{i,a,b}\) 表示考虑前 \(i\) 个物品,第一个医院已用容量为 \(a\),第二个医院已用容量为 \(b\) 是否可行,优化为 \(f_{i,j}\) 表示第一个医院已用容量为 \(j\) 时第二个医院已用容量的最小值。转移为:

\[f_{i,j}=\min(f_{i-1,j-u_i},f_{i-1,j}+v_i) \]

这样背包单次的时间复杂度 \(O(nT)\)。令 \(f_0,f_1,f_2,f_3\) 分别表示 \((1,1)(1,L)\),\((1,1)(L,1)\),\((L,L)(1,L)\),\((L,L)(L,1)\) 的结果。

枚举 \((1,1)\) 在第一类中用的容量 \(W_0\),和第二类中用的容量 \(W_1\)。那么 \((1,L)\) 最少用 \(t_{(1,L)}=f_0(W_0)\),\((L,1)\) 最少用 \(t_{(L,1)}=f_1(W_1)\)。第三类会给 \((L,L)\) 贡献 \(f_2(t_{(1,L)})\),第四类会给 \((L,L)\) 贡献 \(f_3(t_{(L,1)})\),那么我们判断是否有 \(t_{(1,L)}\le T,t_{(L,1)}\le T,f_2(t_{(1,L)})+f_3(t_{(L,1)})\le T\) 即可知道这种方案是否可行。可以预处理前缀 min 省去 \(W_1\) 的枚举,于是这样的时间复杂度为 \(O(nT^3)\),无法通过。

考虑优化,按照 \((x_i-y_i)\) 排序扫描 \(q\) 的时候 \((1,L)(L,1)\) 只决定于 \(i\le q,i>q\),而 \((1,1)(L,L)\) 只决定于 \(rk_i\le p,rk_i>q\),其中 \(rk_i\) 表示按照 \((x_i+y_i)\) 排序后 \(i\) 的排名。因此只需要对前后缀分别跑一个背包,然后在 \(q\) 处拼接即可。这样时间复杂度为 \(O(n^2T)\),可以通过。

仙人掌(三)

100+65+100+20=285,rk9,不会 T2。

T2 绅士 gentleman(数位 dp)

考虑一个比较有启发性的暴力:注意到由于 \(\mathrm{Big}(A)\le 9\),取模之后最多变成个位数,因此暴力把 \(A\) 跑到 \(<M\) 的最大数,然后处理取模,这样最多 \(10\) 次之后由抽屉原理一定会出现循环。

注意到这个可以拓展,如果一次进位到了第 \(k\) 位,那么除了个位以外的更低位一定都是 \(0\),呈现一个 \((+1)000\dots 0x\) 的形态,把这个设计成 \(\mathrm{dp}\),令 \(f_{k,d,x}\) 表示考虑低 \(k\) 位,第 \(k\) 位及以上的最大数为 \(d\),更低位呈现 \(000\dots 0x\) 的形态,此时要使第 \(k+1\) 位发生进位所需要的步数,另外记 \(to_{k,d,x}\) 表示跳到的个位数。

然后就可以从低位往高位拓展,每次尝试将当前位进行进位,并判断能不能跑满。这样可以快速计算 \(F(A,N)\) 表示数 \(A\) 经过 \(N\) 步之后跳到的数,然后再套用上述不断跳 \(<M\) 的做法即可。

仙人掌(四)

T1 卡牌游戏 card(二分)

气笑了。考虑转化一下题意,变成分组使得开头和结尾相同,形如 \(\texttt{(ABC)(CBA)(ACB)\dots}\),假设分了 \(k\) 组,这样实际得分就是组数 \(k\),实际使用卡片数为 \(3k-(k-1)=2k+1\),每组恰好含一个 \(A,B,C\),因此至少使用的卡片数为 \(\min(A,k)+\min(B,k)+\min(C,k)\),直接二分即可。

仙人掌(五)

T3 序列消除 erase(dp 优化)

考虑最朴素的 dp,令 \(f(l,r)\) 表示区间 \([l,r]\) 的答案,枚举颜色 \(c\),设其在区间中的出现位置为 \(k_0=l,k_1,k_2,k_3,\dots,k_m,k_{m+1}=r\),转移为:

\[f(l,r)=\sum_{c=1}^{V}\prod_{i=0}^{m} f(k_i+1,k_{i+1}-1) \]

考虑如何优化,考虑找到 \(c\) 在 \([l,r]\) 出现的最左位置 \(L_{l,c}\) 和最右位置 \(R_{r,c}\),我们发现 \([L_{l,c},R_{r,c}]\) 部分的转移是比较整齐的,将其独立出来,将转移式写成:

\[f(l,r)=\sum_{c=1}^V \left[ f(l,L_{l,c}-1)\cdot \left(\prod_{k=1}^{m-1} f(k_i+1,k_{i+1}-1)\right)\cdot f(R_{r,c}+1,r)\right] \]

假设我们已经 \(O(1)\) 解决了中间部分的查询,此时转移的时间复杂度是什么?注意到此时每个合法区间必有一个端点形如“另一端往左/往右颜色 \(c\) 第一个出现的位置”,因此每个位置往外最多只有 \(O(V)\) 个合法区间,总合法区间数只有 \(O(nV)\),因此加上记忆化后,单次转移要 \(O(V)\),这样的时间复杂度就是正确的 \(O(nV^2)\)。于是只需要预处理“整齐段”的答案,把每种颜色拉出来跑前缀积就可以了。

T4 停机检查 halt(基环树)

Observation: 我们称 \(x=a_i\) 走到 \(c_i\) 的边为重边,其余边为轻边,则整个过程中最多走 \(O(n)\) 次重边。否则重复经过了 \((a_i,i)\) 这个状态,这样成环一定无解。

因此我们尝试优化轻边的跳跃,由于经过重边之后状态固定为 \((c_i,a_i+b_i)\),相当于有 \(O(n)\) 个离线的询问,每次询问形如当前在点 \(u\),坐标为 \(x\),求不断沿着轻边走下一个走到的重边在哪里。首先 \(i\) 向 \(e_i\) 连边把轻边构成的图建出来,容易发现这是一个内向基环树森林,特别的 \(n+1\) 所在的那个连通块是一棵以 \(n+1\) 为根的树。

考虑在基环树上做这个问题。设 \(u\) 所在子树在环上的根为 \(cir_i\),分类讨论最终到达的点 \(v\) 与 \(u\) 的关系:

  • \(v\) 是 \(cir_i\) 子树内 \(u\) 的祖先。令 \(dis\) 为点到根的边权和,这个条件等价于 \(x+dis_v-dis_u=a_v\),即 \(dis_v+a_v=x-dis_u\),因此从上往下 dfs 时开个桶维护 \(dis_v+a_v\) 即可。

  • \(v\) 是环上某个节点 \(cir_j\)。首先让 \(u\) 走到环上,\(x\leftarrow x+dis_u\)。然后点 \(u\) 可以在环上绕圈最后回到 \(v\)。破环成链之后记前缀边权和为 \(s_i\),环上边权总和为 \(S\),环长为 \(m\),设转的最小圈数为 \(k\),则

    \[x+kS+s_j-s_i=a_{v} \\ \Rightarrow k=\frac{a_{v}-s_j}{S}-\frac{x-s_i}{S} \]

    进一步地,可以表示出此时要走的时间 \(T\) :

    \[T=j-i+km=\underbrace{\left(\frac{a_v-s_j}{S}m+j\right)}_{W_j}-\underbrace{\left(\frac{x-s_i}{S}m+i\right)}_{X} \]

    转的圈数应为整数,所以还需要满足 \(a_v-s_j\equiv x-s_i{\pmod {|S|}}\),然后就很简单了,为模 \(|S|\) 的余数开桶,每次在 \(r=(x-s_i)\bmod |S|\) 的桶里二分找到满足 \(W_j\ge X\) 的最小的 \(W_j\) 贡献即可。需要特判 \(S=0\) 的情况,此时一定不会绕圈,若 \(j\ge i\) 则贡献为 \(j-i\),否则贡献为 \(j-i+m\)。

最后不断沿着重边跳,如果成环或是有一个位置无法再次跳到重边就无解,最多跳 \(O(n)\) 次,直到某个重边会沿着轻边跳到 \(n+1\) 为止。这样总体时间复杂度为 \(O(n\log n)\),精细实现可能可以做到线性。

仙人掌(六)

P16458 [UOI 2026] mex plus(图论建模,贪心,线段树分治)

建图但是没想到定向。对于这种二选一的题可以考虑图论建模,给 \((A_i,B_i)\) 连边,然后将选择看做对边定向,如果 \(u\to v\) 表示 \(u\) 去 \(A\) 而 \(v\) 去 \(B\),可以发现这样建图的性质:出度为 \(0\) 的数一定都去了 \(A\),入度为 \(0\) 的数一定都去了 \(B\)。因此 \(\operatorname{mex}(A)+\operatorname{mex}(B)\) 可以被表示为:图定向后,入度为 \(0\) 的最小点与出度为 \(0\) 的最小点之和。

发现度数为 \(1\) 的点是比较关键的,因为这些数只能被定到两类中的一个,设最小的一度点为 \(x\),则两个集合中必定有一个的 \(\mathrm{mex}\) 不超过 \(x\)。假设让 \(B\) 承担这个损失,此时最优的策略显然是把所有的一度点给 \(A\),将所有一度点的边定向外面。

考虑每个连通块内部的定向,我们发现连通块的形态会影响决策:

  • 连通块是一棵树(\(|E|=|V|-1\))。无论如何定向一定至少有一个出度为 \(0\) 的点,从贪心的角度看选择整个连通块中编号最大的点作为根,其他边都定为远离根的方向是最优的,此时对 \(A\) 的限制只有“连通块中点的最大编号”。
  • 连通块有环(\(|E|\ge |V|\))。那么这个连通块至少是一棵基环树,拉一个基环树子图出来,对环定向之后将所有边定为远离环的方向,此时所有点出度都不为 \(0\),对 \(A\) 没有任何限制。
  • 连通块是孤立点。记孤立点最小值为 \(M\),则最后两个序列的答案都要对 \(M\) 取 \(\min\)。

因此我们只需要计算出孤立点的最小值 \(M_0\)、所有一度点的最小值 \(M_1\),以及所有树连通块中点的最大编号的最小值 \(M_T\),答案可以表示为 \(\min(M_0,M_T)+\min(M_0,M_1)\)。其中 \(M_0,M_1\) 只与度数相关,可以在加删边的时候动态维护。但是 \(M_T\) 涉及连通块,在删边时很难处理,套路地考虑线段树分治。用可撤销并查集维护连通块情况即可,时间复杂度 \(O((n+q)\log^2 n)\)。

P12480 [集训队互测 2024] Classical Counting Problem(重构树,树剖,dsu on tree)

Observation. 一组 \((\min,\max)\) 可以唯一确定操作得到的树。

不妨设 \(\min=u,\max=v\),为了得到只包含 \([u,v]\) 的连通块,\(<u\) 和 \(>v\) 的所有点都要被删除,因此 \(u\leadsto v\) 的路径上一定只有 \([u,v]\) 之间的数,在满足此条件的前提下,令 \(C(u,v)\) 表示只保留 \([u,v]\) 中的点后 \(u,v\) 所在的极大连通块,则 \(C(u,v)\) 是满足 \(\min,\max\) 限制下能够得到的唯一连通块。否则假设存在更小的连通块 \(S\) 满足条件,那么对于点 \(w\in C(u,v),w\not\in S\), 一定是断开了 \(w\leadsto u,v\) 中的某点,而这个点一定在 \([u,v]\) 中导致其不能被断开,所以不存在更小的连通块。

回到原题,可以看作求 \(\sum\limits_{u,v} |C(u,v)|\cdot u\cdot v\)。考虑建立原树的大根小根重构树 \(T_{\max}\) 和 \(T_{\min}\),其中点 \(u\) 的子树代表只通过 \(\le u\) 或者 \(\ge u\) 的点能够到达的点集。因此 \(u,v\) 合法等价于 \(v\in T_{\min}(u),u\in T_{max}(v)\),此时 \(C(u,v)=T_{\min}(u)\cap T_{\max}(v)\)。 拆贡献,看做对三元组 \((u,v,w)\) 计算贡献,其中 \(w\) 既在 \(T_{\min}\) 的 \(u\) 子树中,也在 \(T_{\max}\) 的 \(v\) 子树中,贡献为 \(u\cdot v\)。

对于两棵树的情况,套路就是在一棵树上枚举点,在另一棵树上维护信息。贡献为 \(u\cdot v\) 肯定要枚举 \(u,v\) 中的一个,考虑在 \(T_{\max}\) 上枚举 \(v\),则 \(u,w\) 要在 \(v\) 子树中,在 \(T_{\min}\) 上 \(u\) 是 \(v\) 根链上的节点,每个 \(u\) 带来的贡献次数是其子树中 \(w\) 的数量。这个东西就很好做了,在 \(T_{\min}\) 上用树剖维护,操作是对根链 \(\mathrm{cnt}\) 加、查询根链上 \(u\cdot \mathrm{cnt}(u)\) 的和,在线段树上额外维护一个区间 \(u\) 之和即可支持区间加。回到 \(T_{\max}\) 的部分,涉及子树信息可以直接上 dsu on tree,继承重儿子的线段树,然后暴力添加轻儿子,可以做到 \(O(n\log^3 n)\)。

仙人掌(七)

T4 ladder(分块,CDQ分治)

出发点其实比较奇怪,思考为什么终点序列是 \([1,n]\) 的排列。如果没有横杆那么排列就应该是 \([1,2,\dots,n]\),按高度从上到下考虑每条横杆,假设这条横杆跨过 \(x,x+1\),在更高层到达 \(x\) 的那个位置是 \(p_x\),在经过这条横杆时就会拐到 \(x+1\),同理 \(p_{x+1}\) 也会拐到 \(x\),因此这条横杆的作用就是 \(\mathrm{swap}(p_x,p_{x+1})\)。假设我们已经知道了 \(p\),那么能够做到的最小操作次数就是冒泡排序的交换数,也就是逆序对的数量。

因此问题被转化成:维护事件 \((h,x)\) 的集合,每次查询按照 \(h\) 升序顺序遍历事件,对 \([1,2,\dots,n]\) 不断进行 \(\mathrm{swap}(p_x,p_{x+1})\) 操作,求最后得到排列的逆序对数。

考虑分块。以 \(h\) 为第一关键字,\(x\) 为第二关键字离散化所有事件,在离散化后的序列上分块。考虑加入操作怎么做,令 \(a,b\) 分别表示 \(x,x+1\) 沿着 \(>h\) 的横杠继续往下走最后到达的位置,那么这次修改的意义就是 \(\mathrm{swap}(p_a,p_b)\)。于是我们需要支持的操作就是动态添加横杆,查询某个位置沿着后缀最后到达的位置,散块暴力跳,对整块维护 \(to_{k,i}\) 表示经过第 \(k\) 个块中的所有事件后位置 \(i\) 到达的位置,修改时重构即可。并且可以发现删除和添加是等价的,于是只需要支持添加操作,这部分可以精细实现做到 \(O(m\sqrt{m})\)。

对于逆序对的部分,其实就是一个支持交换 \(p_x,p_y\) 的动态逆序对问题。分讨一下,可以发现要求的东西就是 \((x,y)\) 区间中在 \((p_x,p_y)\) 中的元素个数,设数量为 \(C\),则逆序对的变化量 \(\Delta=\mathrm{sgn}(p_y-p_x)\cdot(1+2C)\)。动态二维数点,直接上 CDQ 分治,这部分可以做到 \(O(m\log^2 m)\)。

于是总时间复杂度 \(O(m\sqrt{m}+m\log^2 m)\)。

仙人掌(八)

T2 标签 attach(线段树)

直接二分答案,考虑保留下来的数是否 \(\ge mid\)。将 \(\ge mid\) 的数标 \(1\),其余标 \(0\) 转化成 \(01\) 序列。问题转化成是否存在后缀使 \(1\) 的个数大于删除操作的个数。定义权值 \(w_i\) 如果 \(p_i\ge mid\) 则 \(+1\),若 \(i\) 被删除则 \(-1\),就是询问后缀最大值。注意到答案不增,双指针用线段树维护即可。

T3 图论 graph(模运算,图论,exgcd)

与 [WC2011] 最大 XOR 和路径 类似,我们尝试将路径拆成简单路径和环。异或有很优美的性质就是经过两次会消掉,对应到这题,任意一条边被经过 \(m\) 次就会消掉。考虑图中的任何一个环,可以构造出一种任意次经过环的方法:先走到环上一点,绕任意圈,然后在路径与环的路径上往返 \(m\) 次,由于 \(m\) 次经过一条边的贡献就会消掉,这样就可以在环上走任意圈。设环长为 \(C\),这个环的贡献就是可以任意加上 \(kC\)。

异或可以用线性基刻画表示出的集合,对应到取模就是裴属定理:如果可以走出 \(k_1,k_2,\dots,k_t\) 的倍数,那么可以走出所有 \(\gcd(k_1,k_2,\dots,k_t,m)\) 的倍数。在 dfs 生成树上考虑这个问题,设 \(u,v\) 在树上的距离为 \(w\),找到所有环长的 \(\gcd\) 记为 \(g\),那么能表示出的路径长度就是 \(w+\gcd(g,m)\cdot y\) 的形式。直接找所有环肯定不行,不过只保留本原环即可,其他环可以由本原环拼凑出来,注意一条无向边也是一个特殊的环长为 \(2w_i\) 的环。因此找到所有的本原环,\(g\) 就是所有本原环长和所有 \(2w_i\) 的 \(\gcd\)。

令 \(d=gcd(g,m)\),等差数列中能够被表示出的数需要满足 \(\exists y,x+kb=w+yd\)。这是一个不定方程的形式,用 exgcd 求解即可。整理一下,也就是 \(kb\equiv w-x\equiv z\pmod{d}\),令 \(g_0=\gcd(b,d)\),有解当且仅当 \(g_0\mid z\),然后可以 \(b,z,d\) 同除 \(g_0\),对于 \(kb^\prime\equiv z^\prime\pmod{d^\prime}\),由于 \(\gcd(b^\prime,d^\prime)=1\) 可以用 exgcd 求出 \(b^\prime\) 的逆元作为一组特解 \(k_0\),那么所有可行解形如 \(k=k_0+yd^\prime\)。

用带权冰茶几维护连通性即可。

仙人掌(九)

T3 生成树很爽 tree(MST,并查集,拆贡献)

注意到 \(w_i\le 30\) 非常小,不妨枚举边权进行拆贡献,类比期望的拆法,我们有 \(\sum\limits_{e\in \mathrm{MST}(G)} w_e=\sum\limits_{t=0}^{+\infty}\sum\limits_e [w_e>t\wedge e\in \mathrm{MST}(G)]\)。考虑 Kruskal 算法的流程,只保留边权 \(\le t\) 的边时的图记为 \(G_t\),后面贡献的意义就是:将 \(G_t\) 中的连通块连通所需的边数,也就是 \(G_t\) 的连通块个数 \(-1\),点边容斥一下,对于前 \(i\) 层边数是确定的 \(V_i=(i+1)n\),如果我们能求出 \(E_i\) 为前 \(i\) 层连的边数,贡献就是 \(V_i-E_i-1\)。

于是我们将 MST 弱化成了连通性问题。由于图中的边只会跨越相邻两层,考虑按层从前往后增量处理,我们只关注上一层点的连通关系,开一个 \(2n\) 个节点的并查集,其中 \(1\sim n\) 的点表示上一层节点,\(n+1\sim 2n\) 表示当前层节点,为了方便我们钦定连通块中编号最大的点作为根,这样可以通过根编号的大小判断合并的情况,对于边 \((u,v)\),尝试在并查集上合并点 \(u\) 和点 \(v+n\),如果这两个节点已经连通说明这条边多余,加入的总边数减 \(1\),否则设两点的根分别为 \(u^\prime,v^\prime\),如果 \(u^\prime,v^\prime>n\) 说明这条边在新的一层造成了新的合并贡献,在下一层的转移中应当合并 \((u^\prime-n,v^\prime-n)\)。分析一下时间复杂度,由于成功的合并最多进行 \(O(n)\) 次,这样做均摊的时间复杂度是 \(O(Vn\log n)\)。考虑如何求答案,处理每一层时可以计算出这一层相较于上一层减少的边数 \(c_i\),那么 \(c_i\) 实际是 \(E_i\) 的二阶差分,做前缀和即可得到 \(E_i\)。

T4 次第成章 unfolding(计数 dp)

好厉害的题。考虑序列 \(A\) 可以插入哪些数使得字典序变大。回顾字典序比较:找到后面第一个不等的地方比较大小。可以在一个 \(y<x\) 的位置前面插入 \(x\) 来把 \(y\) 顶掉,其中 \(y=x\) 可以规约到这种情况。于是我们发现能插入的条件很简洁:\(x\) 可以顶掉一个比 \(x\) 小的数,也可以顶掉滚木。设 \(cnt_y\) 表示数 \(y\) 出现的次数,此时插入的方案数就是 \(1+\sum\limits_{y=1}^{x-1} cnt_y\)。涉及数的大小关系,考虑按数从小往大考虑,每次把一种数全部插到序列中,并计算这种数在插入过程中的转移系数。令 \(f_{i,j}\) 表示 \(A\) 中插入了 \([1,i]\) 的数,且此时 \(\sum\limits_{y=1}^{i-1} cnt_y=j\) 的方案数。转移形如:\(f_{i+1,j+k}\leftarrow f_{i,j}\times g_{j,k}\),其中 \(g_{j,k}\) 为转移系数,含义是和为 \(j\) 时插入 \(k\) 个数的方案数。回顾原序列的插入过程,我们可以在已经有 \(j^\prime\) 个数的时候再插入 \(p\) 个,根据上面的分析这部分的方案数就是 \((j^\prime+1)^p\),因此转移就是 \(g_{j+1,k+p}\leftarrow g_{j,k}\times (j+1)^p\)。预处理幂次时间复杂度 \(O(n^3)\)。

仙人掌(十一)

T2 黄金矿工 game(dp,性质分析)

令 \(f_{i,j,0/1/2}\) 表示已经用的交换数量为 \(j\),且目前的连通情况为 \(0/1/2\) 的权值。时间复杂度 \(O(n^2)\),发现很难优化。原因是 dp 太蠢了,先挖掘一下性质:\(11\) 一定选,\(00\) 可以走到的时候决定,只有 \(01,10\) 在决策只会选 \(1\) 时比较特殊。记 \(01,10\) 只选 \(1\) 的数量为 \(k\),那么 Bob 可以反转 \(\min(k,m)\) 个这种位,造成 \(-2\min(k,m)\) 的贡献。设 \(S\) 表示这种选法下连通块本身的贡献,那么答案就是 \(S-2\min(k,m)=\max(S-2k,S-2m)\)。那就很好做了,两种情况分开统计,分别钦定这种选法的贡献为 \(-1,1\) 即可。时间复杂度线性。

仙人掌(十三)

T3 回文串 palindrome(倍增并查集)

萌萌哒也是可以用线段树维护哈希值做的。但是这题其实可以套用萌萌哒的倍增并查集做法。只不过萌萌哒是离线的,此题要求在线,能做依赖于一条性质:点数为 \(n\) 时有效合并的次数只有 \(O(n)\) 个。

首先将 \(S\) 反转一下拼在后面就可以将回文相等转化成子串相等 \(S[l:r]=S[2n-r+1:2n-l+1]\)。直接遍历每一位在并查集上合并是 \(O(\mathrm{len})\) 的。考虑倍增,类似 ST 表的结构,令 \(f_k\) 表示所有长度为 \(2^k\) 的子区间 \([i,i+2^k-1]\) 的连通关系。因为子串相等关系是可以拆分和合并的,这样可以形成一个优美的 pushdown 结构:在 \(f_k\) 中两个位置 \(i,j\) 连通等价于 \(f_{k-1}\) 中 \((i,j)\) 和 \((i+2^{k-1},j+2^{k-1})\) 连通。

对于合并操作,考虑直接暴力合并,如果要合并的两个位置在当前层已经连通则直接返回,否则递归左右进行合并,因为总点数只有 \(n\log n\),这样的有效合并次数只有 \(O(n\log n)\) 的,每次递归下去一定会合并这个结点,均摊下来就是 \(O(n\log n\alpha(n))\) 的,可以接受。

对于询问,相当于要询问目前两个子串 \([l,l+2^k-1]\) 和 \([r,r+2^k-1]\) 是否相同。如果直接递归到叶子判断连通性肯定是不行的,考虑一个类似 pushup 的过程,如果在当前层的 \(f_k\) 中 \((l,r)\) 已经连通就直接返回,否则分别递归 \((l,r)(l+2^{k-1},r+2^{k-1})\) 判断连通性,如果这两个子串都已经连通就直接在 \(f_k\) 中合并 \(l,r\)。可以发现每次递归下去会确定的合并两个结点,那么总合并次数也是正确的。

于是做完了,时间复杂度 \(O((n+q)\log n\alpha(n))\)。

T4 资源分配 resources(dp,单调队列)

二分答案 \(mid\),分 \(<mid,\ge mid\) 转 \(01\) 序列。分析一些性质:

  • 性质 1:操作区间一定是极长的。显然。
  • 性质 1 的推论:操作区间两两包含或分离。证明:若存在操作 \([a,b][c,d]\) 相交但不包含,第二次直接操作两者的交集显然更容易做到。

到这里区间的性质已经支持我们进行区间 dp 了,令 \(f_{i,l,r}\) 表示目前进行了 \(i\) 次操作,能否将 \([l,r]\) 区间全部变成 \(1\)。转移形如分成 \([l,k][k+1,r]\) 分别操作再合并。思考结构能否进一步简化。

我们猜测分开操作也是不必要的。因为如果分别操作了 \([l,k],[k+1,r]\),可以找出这两个区间中长度较长的那个先操作,然后之后的操作全部带上这个区间。性质加强为:

  • 操作的区间一定形成嵌套关系,即 \(I_1\subseteq I_2\subseteq\dots \subseteq I_k\)。

  • 若有解则操作次数是 \(O(\log_2 n)\) 的。每个长度为 \(\ell\) 的全 \(1\) 的区间可以拓展 \(2\ell-1\) 个位置。

对上述区间 dp 进行优化。由于操作区间是极长的,变换维度令 \(f_{i,l}\) 表示操作次数为 \(i\) 时,区间左端点为 \(l\) 时能够取到的最大右端点。考虑转移,不妨枚举 \(f_{i,l}\leftarrow r\) 并判断这是否可行。

枚举上一个操作区间为 \([p,f_{i-1,p}]\subseteq [l,r]\)。把 \(0\) 视作权值为 \(-1\) 的位置,令 \(s,c\) 分别表示权值前缀和以及 \(0\) 个数前缀和,\(v(p)=2(c_{f_{i-1,p}}-c_{p-1})\) 表示选择上一个操作区间为 \(p\) 时的收益,那么当前区间的权值和就是 \(s_r-s_{l-1}+v(p)\),因此可以得到转移条件:

\[f_{i,l}\leftarrow r\Leftrightarrow \boxed{s_r-s_{l-1}+\max_{[p,f_{i-1,p}]\subseteq [l,r]} v(p)>0} \]

考虑优化,按 \(l\) 从大到小扫描线。将每个 \(p\) 看做决策三元组 \((p,F_p,v(p))\),那么能取到 \(r\) 等价于:

\[\exists (p,F_p,v(p)),\boxed{s_{l-1}-v(p)<s_r\wedge r\ge F_p} \]

二元限制不好处理,预处理 \(g(x)\) 表示 \(s_i>x\) 的最大下标 \(i\),可以直接取 \(R(l,p)=g(s_{l-1}-v(p))\),判定条件简化成 \(R(l,p)\ge F_p\)。现在的问题就是要求出满足 \(R(l,p)\ge F_p\) 的所有决策中 \(R(l,p)\) 的最大值,由于 \(g(x)\) 随 \(x\) 的减小而增大,就是要找 \(v(p)\) 的最大值。

分析决策的单调性,容易发现 \(F_p\) 是随 \(p\) 的增大而增大的,否则这个决策被包含一定没用。如果有两个决策点 \(p<q\) 不满足 \(v_p<v_q\),那么对同一个左端点 \(l\) 决策 \(p\) 一定偏序决策 \(q\),因此我们可以维护一个从后往前 \(p\) 递减、\(v(p)\) 递减的单调队列。

  • 插入决策 \(v(l)\) 时从队尾取出 \(v(p)\le v(l)\) 的决策抛弃掉。
  • 在队尾删除变得不合法的决策。删完后队尾的 \(v(q)\) 就是最优决策点。

但是从大到小枚举 \(l\) 时 \(s_{l-1}\) 并没有单调性,这就导致在当前 \(l\) 变得不合法的决策 \(p\) 在之后的 \(l^\prime<l\) 处可能又变得合法。再仔细分析,可以发现其实只保留 \(s_{l-1}\) 取到前缀最小值的 \(l\) 即可,否则如果存在 \(l^\prime<l,s_{l^\prime-1}<s_{l-1}\),\(l^\prime\) 的限制比 \(l\) 更松。在只保留这些 \(l\) 时倒着扫 \(s_{l-1}\) 就是递增的,此时对于同一个 \(p\),\(R(l,p)\) 随着 \(l\) 的减小而减小,已经变得不合法的决策会保持不合法,因此可以单调队列。这样可以做到单层转移 \(O(n)\),总时间复杂度 \(O(n\log^2 n)\)。

仙人掌(十四)

T3 聚拢 merge(计数 dp)

太牛了。考虑转差分 \(c_i\),这样在操作相当于找到左右第一个非 \(0\) 的位置 \(-1\),要最小化 \(a_n-a_1=\sum c_i\)。由于左右部分其实是独立的,可以分别贪心,分别从左右扫一遍,如果当前有非 \(0\) 的位置就直接 \(-1\),其实等价于前后各扫一遍。记 \(1\to n\) 得到的最大值为 \(R\),\(n\to 1\) 得到的最小值分别为 \(L\),那么答案就是 \(\max(R-L,0)\)。

推一下可以发现 \(L=\min\limits_{i=1}^n (a_i+(n-i)),R=\max\limits_{i=1}^n (a_i-(i-1))\)。直接记录在状态里就爆炸了。考虑转化 \(\max(R-L,0)=\sum_x [x\in (L,R]]\),这样 \(\min,\max\) 就被拆成了单点限制。直接前缀和优化可以做到 \(O(nV^2)\)。

T4 长链仪礼 ritual(dp,虚树 / 反悔贪心)

交换使颜色相同可以看作 \((0,1)\) 去找 \((1,0)\) 匹配的过程。进一步分析可以发现,令 \(w_u\) 表示 \(\mathrm{path}(1,u)\) 上 \(a_v\) 的最小值,那么代价有两种:

  • \(v\) 找祖先 \(u\) 进行匹配。代价为 \(w_u\)。
  • \(v\) 与 \(u\) 不在一条链上。代价为 \(2w_{\mathrm{lca}(u,v)}\)。

那么就可以设计一个背包 dp,令 \(f_{u,x,y}\) 表示 \(u\) 子树内有 \(x\) 个 \((0,1)\) 没有匹配,\(y\) 个 \((1,0)\) 没有匹配。如果你脑抽了,可能会觉得子树内能匹配就匹配就是对的,但是由于祖先匹配的存在,子树内可以保留数对不匹配而是去找更高的祖先进行匹配。因此这个优化是假的。

在此题的条件下来自同一子树内的两个点合并一定不优,因此我们并不需要知道 \((0,1)(1,0)\) 具体来自哪些子树,只需要知道子树内匹配的组数即可,换成 \(f_{u,i}\) 表示 \(u\) 子树内匹配了 \(i\) 组的最小代价。转移是简单的。然后你发现建虚树 dp 即可。时间复杂度 \(O(n+k^2)\)。

有高妙的反贪做法,来学一下。考虑之前能匹配就匹配为什么错,假设 \((u,v)\) 在 \(\mathrm{lca}(u,v)=y\) 处合并了,在 \(y\) 往上的某个点 \(x\) 处发现 \(x\) 失配了,那么可以拆散其子树中的已配对点 \((u,v)\),让 \((u,x)\) 构成了一组匹配,\(v\) 变成失配点继续往上寻找匹配。这样反悔的贡献就是 \(\Delta=-2w_y+w_x\)。那么找到匹配对中 \(2w_y\) 最大的那一组,如果 \(2w_y>w_x\) 就可以拆掉这一组。正确性在于拆掉一组之后可以使答案变小,并且 \(x\) 失配和 \(v\) 失配其实是一样的,不会对后续过程造成影响。拿可并堆维护可以做到 \(O(n+k\log k)\),但其实直接启合就好了。


仙人掌(十五)

信号汇聚 relay(区间 dp)

每个点向它下一步跳的点连边可以得到一棵树高不超过 \(h\) 的内向树,代价就是 \((x_i-x_{\mathrm{father}_i})^2\) 之和。可以发现每个点只会向着汇点的方向走,并且这个树中每棵子树都是连续区间,因为同层的两个节点如果走到的父节点交错可以调整使答案更优。

据此可以设计区间 dp,令 \(f_{h,l,r,x}\) 表示树高为 \(h\),区间 \([l,r]\) 内部的点全部汇集到点 \(x\) 的最小代价。由于上述关于子树区间的性质,\([l,r]\) 可以被分成 \([l,x]\to x\) 和 \([x,r]\to x\) 两部分的贡献之和。也就是必定有 \(f_{h,l,r,x}=f_{h,l,x,x}+f_{h,x,r,x}\),那么有效的 dp 状态其实可以简化为 \(L_{h,l,r},R_{h,l,r}\) 分别表示区间 \([l,r]\) 全部走到左端点 / 右端点的代价最小值,那么 \(f_{h,l,r,x}=R_{h,l,x}+L_{h,x,r}\)。

转移考虑每次剥离掉最右边的子树,得到转移:

\[L_{h,l,r}=\min_{k=l}^{r-1} \min_{u=k+1}^r\set{L_{h,l,k}+f_{h-1,k+1,r,u}+(x_l-x_u)^2} \\ \Rightarrow L_{h,l,r}=\min_{k=l}^{r-1} \min_{u=k+1}^r\set{L_{h,l,k}+R_{h-1,k+1,u}+L_{h-1,u,r}+(x_l-x_u)^2} \]

分离变量,可以发现其中 \(L_{h,l,k}+R_{h-1,k+1,u}\) 与 \(r\) 无关,提出来令 \(g_{h,l,u}=\min\limits_{k=l}^{u-1} \set{L_{h,l,k}+R_{h-1,k+1,u}}\),那么 \(L\) 的转移只依赖于 \(u\),即 \(L_{h,l,r}=\min\limits_{u=l+1}^r\set{g_{h,l,u}+L_{h-1,u,r}+(x_l-x_u)^2}\),这样每一层转移只需要 \(O(n^3)\),总时间复杂度 \(O(n^4)\)

posted @ 2026-09-26 11:12  STDJCY  阅读(22)  评论(0)    收藏  举报