2025.9 杂题

模拟赛单独拉出去了,所以这里题会很少。

CF2133F

首先要解决的是一个引爆顺序的问题,如果选的两个区间互相包含了对方中点这个方案显然就不合法,如果其中一方包含了另一方,那么被包含的向包含它的连边,表示一个拓扑序限制。可以发现的是,只要选的区间里面没有自环那整个图一定就无环,这时候只需要在 DAG 上跑一个拓扑排序即可。

然后下一步是解决最小代价问题,这是非常简单的线段树优化 DP,线段挂在右端点上直接做即可。对于输出方案,记录下转移点取出来所有的线段,只考虑相邻的两个线段之间的拓扑序限制,连边跑一下即可,因为显然最终方案里的线段随着左端点递增右端点也是递增的,不然删去被包含的肯定不影响结果,复杂度 \(O(n\log n)\)

CF2134F

首先一步观察就是,对于一个序列,我们称 \(0,2\) 为红点,\(1,3\) 为蓝点,可以得到如下性质:

  • 一对相邻的红点和蓝点贡献一定是 \(1\)
  • 一对相同的红点或蓝点贡献显然是 \(0\),而不同的贡献则一定是 \(2\)

一个序列肯定可以被划分成若干个极长的红色或者蓝色连续段拼起来,所以一个自然的想法就是对红色和蓝色段先分别计算,最后再拼起来。具体来说我们希望处理出 \(r_{i,j}/b_{i,j}\) 表示 \(i\) 个红/蓝色连续段产生恰好 \(j\) 的贡献的方案数,这样统计答案的时候,只需要选 \(i\)\(i+1\) 个红蓝段拼在一起即可。

\(r_{i,j}\) 的计算为例,考虑把相邻的 \(0\)\(2\) 给缩起来,这样每段都是 \(0,2\) 交替的了。然后可以直接 DP,设 \(f_{i,j,k,0/1}\) 表示当前已经分了 \(i\) 段,\(0\)\(2\) 分别填了 \(j,k\) 个,上一个填的是 \(0/2\) 的方案数。一个 \(f_{i,j,k}\) 对答案的贡献就是 \(2(j+k-i)\),注意贡献到 \(r_{i,j}\) 时需要乘上两个插板的组合数,因为这里的 \(0,2\) 被缩起来了。

时间复杂度 \(O(n^3)\)

ABC421G

感觉是费用流板子啊。考虑差分数组,相当于要把每个数变成非负的。对于其中的负数,从源点向它引绝对值的流量;对于其中的正数,从它向汇点引绝对值的流量。然后每个区间再给端点连下带 \(1\) 的费用的边,就做完了。

QOJ13008

首先两条线相交相当于它们是排列的一个逆序对,所以选择的线段必须是排列的一个上升子序列。进一步地因为我们必须要把排列给删空,所以这个上升子序列必须是极长的。

于是直接 DP 就可以做到 \(O(n^2)\)。有两个简单的 \(O(n\log^2 n)\) 做法,一个是转移和区间最值有关系,自然地考虑直接 CDQ 分治,每层的转移可以写成二维偏序然后数据结构维护。还有一个观察是,这个 DP 其实会从一段前缀的所有后缀 \(\max\) 转移过来,于是可以直接上单侧递归线段树。

似乎有 \(O(n\log n)\) 做法,不会。

QOJ14025

其实我好像没太做明白这道题,意识流地记录一下。

考虑先对波特的策略进行调整。对于一个点 \(u\),如果存在点 \(v\) 使得 \(a_u>dist(u,v)+a_v\) 那一定不会考虑在 \(u\) 处合并,称这样的点为坏点,其它的点为好点。可以先跑一遍 dijkstra 求出 \(d_u\) 表示 \(\min_v\{dist(u,v)+a_v\}\),并设 \(col_u\) 表示离 \(u\) 最近的好点。那对于初始不在好点上的波特,显然它的策略是直接走到 \(col_u\) 上去合并,于是假设只剩下好点上的波特。

因为现在剩下的都是好点,从一个好点再走到别的好点去合并代价肯定只会变大,所以接下来这些波特在行走中如果某一时刻在一个好点上重合了一定会立刻合并,发现这形成了一个树形的结构。考虑原图中所有边 \((u,v,w)\) 满足 \(col_u\not=col_v\),将它看成新的边 \((col_u,col_v,d_u+d_v+w)\),接下来要做的大概就是对这些边求个最小生成树状物。

具体实现时,先将答案减去所有好点的 \(a_u\),然后加上最小生成树上的边权和以及全局的 \(\min a_i\) 即可(这是因为我们要规定一个合并的方向,直接规定向 \(a\) 的较小值合并是最优的)。

时间复杂度 \(O(n\log n)\)

P11194

我觉得这题还是挺天才的。

首先每个县必然要构成一个连通块,否则你半路走到别的县肯定去它县城更近。

这个限制看上去很难处理,但是实际上你发现只需要相邻两个块之间都满足就够了。进一步地相邻两个块肯定也是边界处限制最紧,假如有一个边界 \((x,y)\),我们要求 \(dis(x,c_x)<dis(x,c_y)\)\(dis(y,c_y)<dis(y,c_x)\),而又有 \(dis(x,c_y)=dis(y,c_y)+1\)\(dis(y,c_x)=dis(x,c_x)+1\),所以限制等价于每个边界都满足 \(dis(x,c_x)=dis(y,c_y)\)

把同一县的点缩起来建个新树,然后就可以设 \(f_u\) 表示 \(u\) 作为它所在县的县城是否合法,对于向新树儿子的所有边界 \((x,y)\),我们都要限制 \(dis(u,x)\in\{dis(y,t)|col_t=col_y,f_t=1\}\)。直接实现是 \(O(n^2)\) 的,然后注意这个限制和距离相关,直接对每个块上个点分治求一下每个点满足几个边界限制即可,复杂度 \(O(n\log n)\)

代码我先懒得写了。

CF2127F

做的时候挺有感觉的,但是最后差了一步很常见的手法,有点火大。

先翻译下题意,\(f(a)\) 可以看成把序列按照全局 \(\max\) 分段,每一段如果长度不为 \(1\) 会有最大值减去段首的贡献。

这样可能还是稍微复杂,为了方便处理继续改写成,全局 \(\max\)\(1\) 的贡献,\(\max\) 后面有 \(-1\) 的贡献,第一个数有 \(-1\) 的贡献,这样每个位置是否有贡献只和自己或者前面是不是全局 \(\max\) 有关,看着就好算了。

\(calc(n,m,k)\) 表示 \(n\) 个不大于 \(m\) 的非负整数凑成 \(k\) 的方案数,这是经典的容斥插板,不解释。

看上去就要去枚举下这个最大值是什么,因为每次调用一次上面的函数复杂度是调和级数的 \(O(m\log m)\),于是假设当前的最大值是 \(x\)。把正负的贡献分开算,先考虑算正的:

  • 最后一个数必须是最大值,贡献是 \(x\cdot calc(n-1,x,m-x)\)
  • 其余的位置相当于再多钦定它是 \(x\),总共的贡献是 \(x(n-1)\cdot calc(n-2,x,m-2x)\)

接下来考虑负的(省略掉前面的负号):

  • 如果最后一个数有负贡献相当于后两个都是 \(x\),贡献是 \(x\cdot calc(n-2,x,m-2x)\)
  • 考虑第一个位置的贡献,相当于求所有方案第一个数的和。考虑对称性,前 \(n-1\) 个位置上的数期望应该都是一样的,所以算出来前 \(n-1\) 个数的总和除以 \(n-1\) 就好了,贡献是 \(\frac{m-x}{n-1}\cdot calc(n-1,x,m-x)\)
  • 中间剩下的数的贡献,相当于钦定一个位置前面是 \(x\),然后剩下的分析方式和上面差不多,总共是 \((m-2x)\cdot calc(n-2,x,m-2x)\)

最后总的复杂度就是 \(O(m\log m)\)

感觉就是,你发现每个位置的限制都是一样的,所以根据对称性等概率之类的手法去计算应该是个很自然的事,也见过不少遍了,不懂为啥卡在了这里,非常难过。

P10805

纯口胡,还是懒得写。直接条件反射地上一手点分治。

考虑统计跨过分治中心 \(rt\) 的路径,一条路径拆成 \(u\to rt\)\(rt\to v\) 两部分,先考虑前者。

我们希望处理出每个点往上跳到 \(rt\) 后剩下多少油,如果 \(dis(u,rt)\le k\) 则可以一步跳上去,否则倍增找到祖先里第一次加油的地方,往后就和这个点等价了,直接继承过来信息即可。

现在考虑所有 \(rt\to v\) 部分并统计答案。

DP 记录每个位置有多少个正好到这里满油的。首先有一种 \(dis(rt,u)\le k\) 的情况,也就是有些点走到 \(rt\) 时耗了一半油再走过来用完,这个可以在上面预处理的信息排序二分数。否则如果在一段祖先后代链的油是满的,也可以过来产生贡献,倍增找到这段链然后给 DP 数组前缀和一下就能统计答案了。

复杂度 \(O(n\log^2 n)\)

P9331

可以发现任意时刻能走到的点是一段区间,所以转化成能同时走到 \(1,n\) 的最小步数。

通过线段树把图建出来,在返图上跑 \(1,n\) 为源的最短路,记 \(f_{i}=dis_{1,i}+dis_{n,i}\)

则点 \(i\) 答案的上界是 \(f_i\),但是这还不对,路径的形态可能形如从 \(i\) 走到一个别的点 \(u\),然后再从 \(u\) 分差走开,这种策略的答案就是 \(dis_{i,u}+f_u\)。发现你可以直接再保留每个点的 \(f_i\) 跑个 dijkstra 更新下每个点的答案,然后就做完了。

复杂度 \(O(n\log^2 n)\)

P13842

首先如果有 \(a_i<b_i\),只需要选择的区间都有交即可,求一下被覆盖次数最多的点即可。

很容易发现 \(a_i>b_i\) 的点只能选一个,然后剩下的区间 \([a_j,b_j]\) 都要满足 \(a_j<b_i<a_i<b_j\)

发现一件事情,对于 \([b_i,a_i]\) 这种区间如果有包含关系肯定可以删去长的那一个,这样这种区间右端点随着左端点递增了。然后加入一个这种区间后后面区间的贡献你可以线段树直接维护,前面区间的贡献需要 2-side 矩形数点,据说离线下来写 CDQ 分治能过。

做到单 \(\log\) 需要更进一步的观察,发现就是如果一个 \([b_i,a_i]\) 包含了一个 \([a_j,b_j]\),那么 \([b_i,a_i]\) 一定也是没用的。刚才的瓶颈在于 2-side 矩形数点的部分,发现现在因为不存在 \(b_i<a_j<b_j<a_i\) 了,可以直接拆成两个 1-side 矩形数点,直接做就好了。

CF516D

你发现把直径终点提为根之后 \(f\) 随着深度增加是单调的。

然后每个点的贡献可以变成一段链加,容易每次询问做到 \(O(n\log n)\)

ARC199C

第一件事情肯定是考虑怎么判断一个排列对一棵树是否合法。首先根据省选 D1T3 的结论,给每个排列求逆之后,相当于以排列的第一项为根时,对于每棵子树都要满足出现位置在排列上是连续的一段。

为了方便,我们把所有的排列 shift 成 \(1\) 开头,然后预处理 \(P_1\) 的每个区间在其它排列是否也是区间,这样就只需要管第一个排列的限制了。显然这是个区间 DP 的形式,考虑设 \(f_{l,r}\) 表示区间 \([l,r]\) 的方案数,一个区间的决策相当于选区间内一个点当根,然后剩下部分划分为若干段合法的小区间。这个可以再上一个线性 DP 解决,大概是设 \(g_{i,0/1}\) 表示上一个区间端点在 \(i\),有没有选过根。发现你只需要对每个 \(l\)\(O(n^2)\) 的复杂度跑出来所有的 \(g_{i,0/1}\) 就能转移,所以最后是 \(O(n^3)\) 的。

P5979

直接 DP 的复杂度是 \(O(n^2)\) 的,考虑优化。转移的限制是和区间 min/max 相关的,所以可以考虑上一手半在线的 CDQ 分治。

首先很容易对于 \(mid\) 左右的点都处理出来 \([l_i,r_i]\) 表示,另一侧的点在这个区间内才合法。然后在 \(mid\) 右侧扫描线+线段树维护转移即可,复杂度 \(O(n\log^2 n)\)

CF1788F

怎么这都不会做???*2500 啊哥们???

第一步就是直接设 \(f_u\) 表示 \(u\) 到根的异或和,然后一个限制变成 \(f_u\oplus f_v=w\),做的时候先把这个给否决了,因为我以为只知道到根的异或和不方便刻画所有边的异或和,纯糖。然后对一个限制直接连边 \((u,v,w)\),之后判断无解就是容易的了,对每个连通块取一棵 DFS 树检查所有的非树边即可。

考虑如何最小化答案,一条边 \((u,v)\) 的真实权值就是 \(f_u\oplus f_v\),然后发现 \(f_u\) 对答案有贡献当且仅当在树上是奇度点。考察新图的每个连通块,如果存在一个连通块有奇数个对答案有贡献的点答案显然是 \(0\),否则我们无法改变答案,原样输出即可。复杂度线性。

明明也不是没见过的套路啊???不能要了,急眼了。

CF1667D

这题确实就比较神秘了,感觉编不出来怎么想到了。

首先可以发现一条边能被删去当且仅当,此时两个端点的度数加起来是偶数。

考虑一点特殊的情况:一个点下面挂着一些叶子。可以玩出来叶子数量超过 \(2\) 一定无解。对于一个叶子来讲,它到它父亲的边在删去时的限制一定是,两边的度数都是奇数。那对于挂着叶子的这个点,它到父亲的边在删去时要满足两边的度数都是偶数。

发现我们可以把边分为奇边和偶边,从下往上决定每条边的奇偶性,具体来说根据到儿子边奇偶性的数量决定到父亲边的奇偶性,如果当前点度数是偶数那必须是奇边等于偶边,否则是奇边比偶边恰好多 \(1\),如果做不到就是无解。

构造是容易的,每个点周围的边一定是奇偶交替地删,如果要删自己到父亲的边直接输出,否则递归到儿子即可,复杂度线性。

CF1767F

好像春天的时候看过一次,现在又忘了,只记得是造莫队指针了/qd

首先有一个很显然也很愚蠢的四维莫队做法,值域分块即可支持加入删除,太无脑了这里略去。

考虑 dsu on tree 的过程,我们把过程中每次加入和删除操作写成一个序列,则正好加完一个子树的时刻会对应这个序列的一个前缀。那么询问两棵子树其实就变成了,询问这个序列的两个前缀。而这个序列的长度是 \(O(n\log n)\) 的,那复杂度自然就是 \(O(n\sqrt{n\log n})\) 了,虽然但是我还是懒得写代码

CF1603E

评价是 \(O(n^6)\) 是弱智,最难的是下一步。

考虑从小到大依次插入每种数,设 \(cnt_i\) 为数字 \(i\) 的个数,\(s_i\)\(i\times cnt_i\) 的前缀和。

考虑判定合法,相当于对所有 \(l,r\) 都有 \(s_r-s_{l-1}\le l\cdot r\),显然 \(l\) 会直接取到整个序列的最小值。

于是枚举整个序列的最小值,直接设 \(f_{i,j,k}\) 表示当前考虑到数 \(i\),一共插了 \(j\) 个数,当前的 \(s_i\)\(k\)

直接转移的复杂度是 \(O(n^6)\),考虑优化。把题目限制带入 \(l=1,r=n+1\) 可以得到 \(\sum(a_i-a_1)\le a_1\),而 \(a_1\) 的大小其实是线性的,所以说把 \(k\) 那一维改成 \(\sum(a_i-mn)\) 的值即可,这样这维的大小就砍成 \(O(n)\) 了。

发现这样还会使得转移枚举 \(i\) 插入几个的复杂度变成调和级数,所以是 \(O(n^4\log n)\) 的,其实已经可以通过了。更进一步地,发现 \(mn\) 的取值只有最大的 \(O(\sqrt n)\) 种,所以其实是 \(O(n^{3.5}\log n)\) 的。

CF516E

这题可能确实不太难,但是我是数论苦手。

首先当 \(n,m\) 不互质时,根据裴蜀定理两边的人 \(i,j\) 能相遇当且仅当 \((i-j)\mid\gcd(n,m)\),所以说两边都按 \(d=\gcd(n,m)\) 分类后,可以转换成若干种 \(n,m\) 互质的情况,答案在每一类取个最大值即可。

不妨再假设此时 \(n>m\)。可以发现如果我们求出男生的最大时间 \(t\),除非 \(t\) 比某个初始不开心女生的编号还要小,否则答案就是 \(t\)。这是因为考虑 \(t\) 之前的 \(m\) 个时刻会涉及所有女生,显然至少有一方会是开心的。所以只需要考虑如何求 \(t\)

假设有某个男生 \(i\) 开心了,那么会让女生 \(i\bmod m\) 开心,然后让男生 \((i+m)\bmod n\)\(m\) 天后开心。可以用最短路描述这个过程,连边 \(i\to (i+m)\bmod n\) 边权 \(m\),然后初始开心的男生 \(i\) 连边 \(S\to i\) 边权 \(0\),初始开心的女生 \(i\) 连边 \(S\to i\) 边权 \(i\)。这样跑一个从 \(S\) 开始的最短路,最长的到某点的最短路就是答案。

问题在于图的规模太大。观察一下可以发现扔掉 \(S\) 后图是个大环(因为 \(n,m\) 现在互质了),而大环上被 \(S\) 连到的点最短路都是确定的,不妨成为关键点。按顺序取出环上这些关键点,则只需要对于每相邻两个关键点,求一下下一个点前驱的最短路即可,由于环上一条边的长度都是 \(m\),所以这是好算的。

求环的顺序可以任选一个起点,然后解同余方程算其它点步数,算最短路时同理,复杂度 \(O(n\log n)\)

P11695

首先为了方便,把所有的区间都变成闭区间。用 \((ql,qr,t)\) 表示时刻 \(t\) 的一次询问 \([ql,qr]\),同理用 \((l,r,tl,tr)\) 表示时刻 \([tl,tr]\) 内的一次操作 \([l,r]\)

对询问做猫树分治,假设现在的分治区间是 \([l,r]\),要处理跨过 \(mid\) 的询问。对于一个要处理的询问,可以把能影响它的操作分为三类:跨过 \(mid\) 的,被左半区间包含的,被右半区间包含的。

先考虑处理跨过 \(mid\) 的操作对询问的影响,我们希望用这些区间向中点两侧覆盖出尽量长的长度。比如要求向左最远覆盖到哪,则一个操作 \((l,r,tl,tr)\) 能更新的询问 \((ql,qr,t)\) 满足 \([l,r]\subseteq[ql,qr]\)\(t\in[tl,tr]\)。对时间进行扫描线,开一棵线段树对每个位置维护当前以它为左端点的操作最小的右端点,扫到操作就扔进线段树里(或从中删除),扫到询问相当于查询 \([ql,mid]\) 里第一个 \(\le qr\) 的位置,线段树二分即可。

再考虑使用两边的区间能不能填满剩下的部分。同样以左边为例,我们希望对每个询问求出从左端点开始向右最远能填到哪。现在考虑对序列从左往右扫描线,使用数据结构维护每个询问向后填线段的过程。具体来说以时间为下标建线段树,维护每个时间的询问当前向右延申到哪,扫到一个询问就加入线段树并初始化成 \(ql\),扫到一个操作相当于将一段时间区间内的询问对 \(r+1\)\(\max\)。扫完一个位置 \(i\) 后,取出线段树上所有值为 \(i\) 的询问弹掉,因为这意味着这些询问在 \(i\) 这个位置断开了。

右边也是同理的,求出这些信息后容易判断一个询问的答案。每个操作区间会在分治树上的 \(O(\log n)\) 个点被用到,所以时间复杂度 \(O(m\log^2 n)\)

P9983

这么牛??这么牛??

下文称被感染的点为黑点,没被感染的点为白点。

先考虑特殊性质,即所有点都是黑点的情况。考虑当前最深的需要被染黑的点,能染到它的点显然都在其 \(x\) 级祖先(\(x\) 表示这组询问的天数)的子树内,显然选其它的点效果都不如直接选 \(x\) 级祖先来的大,于是我们得到了一个正确的贪心策略。

从下往上维护这个贪心过程,记录下每个点的覆盖状态和子树内最远未覆盖点/能向外覆盖的距离即可,容易做到 \(O(nq)\)

对于一般的情况,尝试直接扩展下这个思路。首先设 \(c_u\) 表示离 \(u\) 最近的白点与 \(u\) 的距离,容易 BFS 预处理出来,那么一个点能被选必须满足 \(c_u>x\)。上面的基本思想还是成立的,找到当前最深的需要染黑的点 \(u\),我们希望快速求出最浅的 \(v\) 满足 \(dis(u,v)\le x,c_v>x\),然后直接选择 \(v\) 即可,正确性同上。于是问题变成了如何快速找到 \(v\)

直接用数据结构维护 \(v\) 好像比较困难,但是令 \(p=\text{LCA}(u,v)\),可以发现这么一个事实:当 \(v\) 最浅时,对应的 \(p\) 也一定最浅,否则使用反证法,容易导出矛盾(要么当前最深的要染的点不是 \(u\),要么 \(v\) 可以向上移动)。这启发我们去找最浅的 \(p\),然后去找 \(p\) 对应的 \(v\)

假如确定了 \(p\),拆开 \(dis(u,v)\) 的式子可以发现,\(v\) 直接取 \(p\) 子树内深度最小的 \(c_v>x\) 的点即可。注意到这个点在哪只和 \(p\) 自己有关,所以同样可以提前预处理出每个 \(p\) 对应的 \(v\)


\(dis_p\) 表示 \(p\) 离它对应 \(v\) 的距离,\(b_p=x+dep_p-dis_p\),则 \(p\) 合法相当于 \(dep_u\le b_p\)。这时候一个简单的想法是,直接倍增去找到 \(p\),但是有个问题是 \(b_p\) 随着 \(p\) 向上跳不是单调的。考虑修改 \(v\) 的定义,不再限制 \(v\) 必须在 \(p\) 的子树内,这样 \(dis_p\le dis_{fa_p}+1\),而 \(dep_p\) 向上跳一次一定减少 \(1\),所以此时就有单调性了。

如何说明这样做的正确性?发现这样修改后正确的 \(v\) 也仍一定能被我们找到,假如一个 \(p\) 对应的 \(v\) 在子树外则 \(p\) 跳到真正的 \(\text{LCA}\) 上去也一定合法。找到 \(v\) 后,只需要再实现一个 \(x\) 领域覆盖并支持后续单点查询,使用点分树就好了。

时间复杂度 \(O(nq\log n)\)


实际上并不需要这么麻烦,这题的复杂度还能做到更优。

同样有一个事实是答案的量级是 \(O(\frac{n}{x})\) 的,这很容易理解。

对于当前最深的需要染黑的点 \(u\),直接枚举它的 \(0\sim x\) 级祖先为 \(v\)\(\text{LCA}\),然后根据预处理的信息找到 \(v\) 即可。对于 \(x\) 邻域覆盖,首先 \(v\) 子树内的点一定会被删掉,可以 DFS 一下 \(v\) 的子树并在遇到被删过的点时跳出,这部分均摊复杂度正确。考虑 \(v\) 子树外的部分,给 \(v\)\(0\sim x\) 级祖先打上一个形如“子树内距离不超过 \(y\) 的点会被删去“的标记,这样以后每次取出一个新的 \(u\) 之前先检查下其 \(0\sim x\) 级祖先有没有覆盖到自己即可。

这样单次询问的复杂度降为 \(O(x\cdot\frac{n}{x})=O(n)\),最后总复杂度 \(O(nq)\)

代码建议看其它题解的,不放了。

ARC118E

看上去就是容斥题,先考虑 \(P\) 确定的情况,只需要钦定若干个点被经过即可。

那么对于 \(P\) 没有被完全确定的时候,尝试 DP 的时候边填排列边容斥,然后我只能编出来一些复杂度极高的做法。

正确的姿势应该是,把对着排列 DP 改成对着路径 DP。把上面的容斥套过来,相当于对一条路径钦定上面的若干个点对应一个 \((i,P_i)\),然后计算有多少个排列满足条件。直接记 \(dp_{i,j,k,0/1,0/1}\) 表示当前走到了 \((i,j)\),被钦定的点里开始有 \(k\) 个是不确定了,后两个 \(0/1\) 记录的是当前行/列有没有被钦定过的数。

时间复杂度 \(O(n^3)\)

ARC121E

容斥之后是模板树上背包。

ARC134F

官解的转化很不是人,但是好像可以从集合划分容斥的角度解决,比较深刻。

目前的多项式水平太差了,日后回来继续阅读详细揭秘:集合划分容斥的容斥系数 - 洛谷专栏

P8861

特殊性质很明显在提示猫树分治,此时只需要实现给所有 \(l\) 做 chkmax,给所有的 \(r\) 做 chkmin。同时为了支持查询,相当于要对每个 \(i\) 维护左/右端点在这里的线段的数量 \(cnt_i\),以及 \(i\times cnt_i\) 的值。

直接 seg beats 固然是可行的,但这里有个更有趣的均摊做法。对于 \(l/r\) 相同的线段,用并查集把它们缩在一起,然后对左右端点分别开一个堆,里面维护所有的并查集连通块和对应的端点位置。这样一次修改的时候,不断取出堆顶需要修改的连通块,最后把它们合并起来即可,这样均摊一次修改是 \(O(\log n)\) 的。

考虑一般的情况,那就直接上猫树呗。大体的处理方式和上面基本是一致的,只是修改的时候如果修改区间被左右子区间完全包含,会导致当前挂在这个区间上的线段往左右儿子下放。发现这里直接把它们暴力扔下去就是对的,因为一个线段只会被扔下去 \(\log\) 次。

最后的复杂度就是 \(O(q\log^2 n)\)

HT-078-NOI T1

除了起点以外,每次显然只能走到直径端点上。考虑找出来直径中点(为了方便可以给每条边之间加新点,这样中点一定在某个点上),则要求就是相邻的两个点是来自不同子树的端点。于是现在容易直接矩阵快速幂做到 \(O(n^3\log t)\)

这题看上去就避免不了矩阵快速幂,矩阵乘法显然不好优化,考虑从矩阵大小上入手。发现任意时刻我们关心的不是具体在哪个直径端点上,而是有多少个其它端点能去,由于中点的每棵子树的大小和不超过 \(n\),所以只有 \(O(\sqrt n)\) 个状态。

于是矩阵大小可以压到 \(O(\sqrt n)\),最后的复杂度是 \(O(n\sqrt n\log n)\)

P12789

假设有一个总和为 \(S\) 的区间,用区间内的数参加了 \(c\) 次婚礼后被删空了,那么有 \(S\equiv cR\pmod D\),同时这个区间的价值可以被确定为 \((S-cR)/D\)

显然为了使区间价值最大,\(c\) 会取最小的满足条件的正整数。所以如果一个区间能被删空,它对答案的贡献就是确定的了。如果我们能做到判断一个区间是否可以被删空,整道题就是容易的了。

一个暴力的想法是,设 \(f_{l,r,x}\) 表示区间 \([l,r]\) 剩下的数模 \(D\) 是否可能为 \(x\),这样如果 \(f_{l,r,0}\) 为真则区间可以被删除。注意到这里的 \(x\) 一定可以被表示为 \((S-cR)\bmod D\) 的形式,且我们同时有一个性质:如果 \(x=(S-cR)\bmod D\) 可行,那么对于 \(c'<c\)\(x'=(S-c'R)\bmod D\) 也一定是可行的,因为你可以干脆舍弃掉后面的几次婚礼。

根据上面的性质,考虑将状态简化成设 \(f_{l,r}\) 表示区间 \([l,r]\) 最多能参加几次婚礼。转移只需要先枚举断点 \(mid\)\(f_{l,mid}+f_{mid+1,r}\) 更新,最后判断下能不能再多删一次即可。这样对每个区间,如果最小的满足 \(S\equiv cR\pmod D\)\(c\) 不超过 \(f_{l,r}\),区间 \([l,r]\) 就能被删空。

最后只需要重新做个线性 DP,设 \(dp_i\) 表示 \([1,i]\) 的答案,可以直接转移到 \(dp_{i+1}\),或者转移到 \(j>i\)\([i+1,j]\) 能被删空的 \(dp_j\)

时间复杂度 \(O(n^3)\)


下面是南外的图论专题。

P6841

?这不就是 NOI2020 D1T1 吗,拆点矩阵快速幂即可。

CF578F

结论是给格点做黑白染色后,其中一种颜色要连出生成树,跑矩阵树定理即可。

P7531

新建一对源汇 \(s,t\)\(s\) 连所有发送者,所有接收者连向 \(t\),然后 \(t\) 再向 \(s\) 连上这么多条边。

可以发现现在一种方案能对应一种欧拉回路,所以跑个 BEST 定理即可。

BEST 定理可以去参考 do_while_true 的博客。

CF1610F

\(a(u)\) 表示与 \(u\) 相连的边的边权和,答案的上界是满足 \(a(u)\equiv 1\pmod 2\) 的点的数量。

尝试直接构造取到这个上界,首先有一种偏归纳的做法。考虑图上的两条边 \(x\to y\)\(y\to z\),如果它们的边权相同尝试把这条边缩成 \(x\to z\),显然这不会改变答案的上界。不断重复下去,最后图会被缩成若干环和链,且上面的边权都是 \(1,2\) 交替的。惊奇地发现,这时候对每个环/链任意朝同一方向定向就直接对了,而要把缩的边还原到原图上也是容易的。

上面的做法实现上大概比较有难度,还有个更直接的构造方法。让我写这个我好像只会带 \(\log\)

这个形式其实也有点欧拉回路的意味在,尝试靠拢一下。先建源点 \(S\) 连向所有奇度点变成欧拉图(认为边权为 \(1\)),然后跑一个欧拉回路出来按照 DFS 的顺序定向,同时要求优先走和上一条边边权相同的边,我们考察一下所有 \(a(u)\) 是奇数的点:

  • 如果它原来度数是奇数,去掉 \(S\) 连向它的那条边后刚好符合条件。
  • 如果它原来度数是偶数,那么恰好会有一次从 \(1\) 切换到 \(2\) 的时刻,也符合条件。

所以这样构造取到了上界,显然复杂度线性。

CF1062F

显然我们只需要做到吗,判断一个点和拓扑序比它大的点里,没有到达关系的点数是不是 \(0/1\)

考虑拓扑排序的一个性质,任意时刻队列内的点之间没有到达关系。假如取出一个点 \(u\) 之前队列里只有这一个点,那就说明拓扑序更大的点它都能够到达了。如果队列的大小大于 \(2\),那显然就不合法了,考虑队列大小为 \(2\) 的情况,假如另一个点为 \(v\)

要判断的其实是这么一件事:后面是否存在 \(v\) 能到但是 \(u\) 不能到的点。如果存在这么一个点,那么一定可以从 \(v\) 的后继 \(w\) 中找到这种点,因为越靠后的点 \(u\) 越容易到达。那什么样的后继 \(w\) 不合法?事实上就是当前剩余入读恰好为 \(1\) 的不行。复杂度 \(O(n+m)\)

自己做的时候卡在了最后一步,什么水平?/qd。

CF1477D

题本身确实很牛,但感觉太神秘了啊。。。

嗯好的,假如图已经被定向好了,答案应该是什么?考虑上道题求的东西,如果一个点和其它所有点之间都有到达关系,那么无论怎么拓扑排序这个点的位置都是确定的,所以可以猜测答案就是这种点数,理解很容易。

那现在要干的事情就是,给边定向成 DAG 并最小化这种点数。考虑当前如果存在一个点度数为点数减 \(1\),那无论如何它都会成为上面这种点,可以提前把它放到拓扑序最前方然后删掉它,不断重复这个过程。

删完了怎么办?接下来要直面构造了。考虑这张图的补图,显然每个连通块都不会是孤立点,我们考虑把补图的每个连通块拆成若干个菊花(???哥们你怎么考虑到的),你会发现对于每个菊花,你可以分别按照【叶子+根】和【根+叶子】的顺序取拓扑序满足对位不相同的条件,而每个菊花之间的边你也都可以定向使得之间独立,那就做完了啊??

具体实现,你只需要取补图的一个生成森林。把一棵树拆成若干个菊花是容易的,直接增量构造即可。

时间复杂度 \(O((n+m)\log n)\)

ABC277H

经典的 2-SAT 限制值域的问题,建若干形如表示 \([a_i\ge x]\) 的点即可。

P6898

好大神的题目哦哦。

一个暴力的做法是暴力枚举两个子集的限制,然后容易变成 2-SAT 问题。注意不需要 \(O(n^2)\) 枚举,枚举其中一个对另一个双指针就好了,跑强连通分量使用 Kosaraju+bitset 一次是 \(O(\frac{n^2}{w})\) 的,所以这样做是 \(O(\frac{n^4}{w})\),已经能过了。

但是这比较无趣,考虑一些更大神的性质。枚举一下限制较大的子集,建立一张新图,在距离超过这个限制的点之间连边,则可能合法相当于这个图能被划分成两个子集满足同一子集内没有连边,也就是二分图!考虑限制从大到小的过程会在这个图里加边,如果加边后出现了奇环那就没救了,直接跳过。如果会多一个偶环,发现对染色方案合法性没有影响,也就是产生连通块合并的时候才需要重新染色。

那也就是说,只有加的边发生在连通块合并或者出现奇环之前,当前的限制值才可能是有用的,有用的值只有 \(O(n)\) 种!然后二分另一个集合的限制再跑 2-SAT,这样是 \(O(n^3)\) 的。

还可以做到更优,对这 \(O(n)\) 个值上整体二分确定另一个集合的值,可以 DP 出来复杂度是 \(O(\frac{n^2\log n}{w})\)

P5540

比较神秘的科技,稍微学习一下。

首先把一棵生成树看成平面上的点 \((\sum a,\sum b)\),那么很经典地最优的点肯定在下凸壳上。

但是这个凸壳好像很难求出来,所以要上个科技。大概就是先求出 \(\sum a\) 最小和 \(\sum b\) 最小的两个点出来,它们肯定在凸壳上,不妨分别记为点 \(A,B\)。现在尝试在这个基础上加入新的点,考虑 \(AB\) 左下方使得三角形 \(ABC\) 面积最大的点 \(C\),这个点一定也在凸壳上,列出来叉积的式子发现找出这个点也只需要再跑一遍 MST,然后递归到 \(AC,CB\) 继续做即可。

复杂度是凸包点数乘上 \(O(m\log m)\),据说 NOI2022 D2T3 其实也用的这个科技。


posted @ 2025-09-04 08:14  KingPowers  阅读(102)  评论(0)    收藏  举报