Training-“还笑祝你定闪耀璀璨”
P10303 [THUWC 2020] 报告顺序
紫。
可以发现这个东西就是类似于一个分段一次函数,所以如果没有 \(c\),绝对值大小一定是单调递增的,只用维护正负的最大和最小值。
但是可以发现 c 会让绝对值的变化不单调,考虑到因为改变的值很小,所以只用记录绝对值 \(\le nc\) 的值是否存在,状压就完了。
CF1500D Tiles for Bathroom
紫。
可以发现 \(q\) 很小,应该是一个和 \(q\) 相关的复杂度。
因为长度肯定是单调的,考虑以每个点作为右下角,那么它可以到的左上角就是求出每个颜色到这个点的切比雪夫距离的第 \(q+1\) 小值。
因为每个点的前 \(q+1\) 小值一定被 \((i-1,j),(i,j-1),(i-1,j-1)\) 包含,所以可以直接归并,注意细节。
P7213 [JOISC 2020] 最古の遺跡 3
黑。
可以发现如果一个数被留下来,那么它的值就是前面所有留下来的柱子中没有出现的小于它原本长度的最大值。
所以没有留下来的值一定是 \(1\) 到当前值都出现过,就可以维护留下来的值包含 1 的连续段。
如果没有必须出现两次的要求,那么可以直接延迟钦定,\(f_{i,j}\) 表示 \([1,n*2]\) 中 \([1,j]\) 的位置已经确定。
考虑将每个数字的两个相互区分,然后除以 \(2^n\)。
对于留存下来的值,每个值域上的连续段对应的原值是可以简单 dp 的,这部分可以 \(n^2\) 预处理,\(g_{i,j,0/1}\) 表示前 \(i\) 小的数,用了 \(j\) 个,最后一个数是否已经选过。
对于不留下的值,它的可选数就是 \(2*x-n*2+i\),直接贡献上去就可以了。
CF1666E Even Split
青。
显然极差有可二分性,判断极差是否可行可以再套一个二分,就是二分一个最小值,因为合法的一定是中间的一段,前面的偏小,后面的偏大。
判断可以记录目前满足条件可以到的最近/最远点 \(xr_i,xl_i\),有:
\(xr_i=min(xr_{i-1}+r,a_{i+1}),xl_i=max(a_i,xl_{i-1}+l)\)
最后求答案倒推即可。
CF1809E Two Tanks
青。
可以把水视作一条线段,倒水就相当于移动线段的位置,要求线段不碰到左右端点且不离开原点。
那么任意时刻有 \(-a\le p+t\le 0,0\le t+p+x \le b\) 时,答案就是 \(p-s_n\)。
显然对于每个长度和 \(x\),所满足条件的点一定构成一段区间。
先考虑在区间左边的部分,那么必然在某个时刻全部在左区间或者顶到左端点,那么此时这部分都处在同一个状态,只跑其中一个就可以了,在 \(r\) 右边同理。
CF1774F2 Magician and Pigs (Hard Version)
紫。
个人认为比上面两个简单,首先可以发现每个猪的存在情况是单调的,而且每个操作进行的结构是一个类似于树状数组的东西,大概长这样:
1 2 1 3 1 2 1 4 1 2 1 3 1 2 1 5
数字表示到第几个 3 操作。
对于一个数,就可以类似于线段树二分的去做他,对每个 3 操作为最高点的那一段区间要减去的和求出来,然后判断就行了,但是因为 3 操作很多,这个就会炸掉。
观察易得,每次和至少 \(*2\),所以有效的部分就是 \(\log\) 级别的,只需要做这些。
有很多 corner case,类似于如果前面 2 操作的和为 0,是不计入的,要额外统计贡献。
P13272 [NOI2025] 序列变换
黑。
将修改叫做 \(i->j\) 的移动,先考虑它们的移动方式,一种是每个点只有一个方向,一种是从两边往中间移动,最后在一个点两个方向各做一次。
假设右移在前,记此时中间的值为 \(x\),然后进行左移,记 \(x\) 右边的值为 \(y\),那么 \(x\le y\) 的时候才能完成移动,交换操作顺序也是一样的。
因为有一种情况是要移到同一个点,所以我们关心在最后一次移动前两个值的大小关系。
首先考虑从每一个点开始,向右/向左移动到不能再动,然后在这些点可以到达的点加入编号,关心大小关系,考虑排序然后双指针,但是 \(O(n^2\log)\) 显然不行。
考虑移动的时候值的变化,以右移为例:
假设开头和结尾奇偶性相同,最后留下的是 \(a_1-a_2+a_3-a_4+a_5\) 这个显然是从 1 开始的,所以有 \(a_1-a_2>0\) 所以必然有从 3 开始的最终值小于从 1 开始的。
如果不同,留下的是 \(a_1+a_2-a_3+a_4\),同理从 3 开始的最终值大于从 1 开始的。
所以奇偶性分开处理后就是有序的,归并一下就行了。
然后第一问就可以随意处理了,这里注意一下还有一个右边只有一个值的情况,额外贡献一下,但是第二问可能会重,考虑怎么去。
第一个是如果在移动的过程中,移到的点已经等于 0 了,那么应该立即停下,否则就会与从中间断开的一样,多算一种。
第二个是一个点做两次,但是最后都变成了 0,可以对比系数:
向 \(a_3\) 移动是:\(a_3-a_2+a_1-a_4+a_5=0\),向 \(a_5\) 移动是 \(a_5-a_4+a_3-a_2+a_1=0\) 这两个是一样的。
而且有 \(a_3-a_2+a_1=a_4-a_5,a_5>0\) 所以 \(a_3-a_2+a_1\le a_4\) 一定是可以操作的。
所以考虑直接去掉两边相同的情况,向左或向右移动最后得到全 0 的也只用留一个。
CF1208G Polygons
紫。
可以发现如果 \(x\) 边形被选了,那么 \(x\) 的因子都会被选,而且所有的多边形都有公共顶点。
从小到大去考虑,如果要选 \(x\),那么有多少点是在这里才出现的,显然是 \(\varphi (x)\),其余的因为最优情况要选因子,所以都被选过了。
因为 \(x|d\) 必有 \(\varphi (x)<\varphi (d)\),所以直接排序取最小的就行了。
CF1887C Minimum Array
青。
遇区修想差分,然后就有一大堆做法,最简单的是主席树+哈希+线段树二分。
官解的做法是如果差分数组中的第一个非零数为负,那么它的字典序一定小于原数组,然后清空标记,继续重复此过程,线段树维护即可。
CF464E The Classic Problem
黑。
其实是简单的,考虑求最短路的过程,就是从一个点出发,然后不断把堆中相对较小的点取出来。
可以发现这个东西的复杂度瓶颈在如何比较两个点的值的大小关系,以及每次转移的时候的复制。
因为涉及复制,考虑主席树,每次线段树二分找到前面的第一个 0,比较的话哈希找到第一个不同的点就可以了。
CF526F Pudding Monsters
紫。
依然是简单的,暴力就是从每行开始
考虑分治,每次看跨过中间分开的这条线的矩形数量,可以发现是正方形就是要求 \(i-j=max-min\)。
可以发现 \(min\) 是单调不升的,\(max\) 是单调不降的,所以当 \(i\) 确定时,\(j\) 只有四种情况。
\(max_i>max_j,min_i<min_j\) 那么就只有一个位置有贡献,所以直接判断就是对的。
\(max_i>max_j,min_i>min_j\) 那么此时 \(i\) 的贡献就是 \(i-max_i\),对 \(j-min_j\) 开桶即可。
\(max_i<max_j,min_i<min_j\) 那么此时 \(i\) 的贡献就是 \(i+min_i\),对 \(j+max_j\) 开桶即可。
\(max_i<max_j,min_i>min_j\) 对 \(max_j-min_j+j\) 开桶。
扫描线就完了,用线段树带个 \(log\) 也行。
CF1100F Ivan and Burgers
紫。
有一个做法是直接上猫树,但是有个更简单的,就是可以发现我们要求的东西就是 \([l,r]\) 的线性基,那么可以考虑以每个 \(r\) 作为右端点的每个元素编号尽量大的线性基。
那么考虑从前往后去插入一个数,如果这个位置的编号小于它,那么就交换两个值,然后在继续插入这个新的。
P8337 [Ynoi2004] rsxc
黑。
神人题,波动过的,写上面的是为了写这个。
考虑满足条件的区间就是有 \(2^k\) 种数,线性基大小为 \(k\),根据上面的方法,倒着跑一遍就可以跑出每个 \(k\) 对应的可行区间,就是当前点线性基的第 \(k\) 和 \(k+1\) 大值之间。
然后第二个限制可以暴力双指针,求交,这样就是一些左右端点都单调的区间。
就可以发现最后贡献到查询区间的一定是一段完整区间+一些左端点到 \(r\),所以可以提前预处理区间的前缀和以及左端点前缀和。
至于找分割点,预处理大于每个点最小的 \(l,r\) 的区间编号就可以了。
P8283 「MCOI-08」Dantalion
黑。
不是人。
和上面是一样的,但是要卡常,首先找区间的部分可以记录 \(pre\) 和 \(nxt\),然后加入的时候判断就行了。
空间的话可以发现这个范围是精心设计的,用后 20 个二进制位记录编号,前面的记录前缀和就可以省掉 \(\frac{2}{3}\) 的空间。
统计答案的部分比较人类,粘一下:
il ll calc1(int k,int l1,int r1,int x)
{
if(l1>=r1) return 0;
return 1ll*(r1-l1)*x-(r[k][r1]>>20)+(r[k][l1]>>20);
}
il ll calc2(int k,int l1,int r1)
{
if(l1>=r1) return 0;
return (l[k][r1]>>20)-(l[k][l1]>>20);
}
inline ll solve(int l1,int r1)
{
ll res=0,t=0;
int v=min(l2[cnt],l2[r1-l1+1]);
for(int k=0;k<=v;++k)
{
int x=(l[k][r1]&s)-1,y=(r[k][r1]&s)-1;
res+=calc1(k,max(l1-1,y),x,r1+1)+calc2(k,l1-1,y);
}
return res+1ll*t*(r1+1);
}
CF1539F Strange Array
紫。
数据结构板子,将小于当前数的记为 -1,大于的记为 1,最后的结果只和所选段数的和有关,因为其他数之间可以相互抵消。
然后就是找到最大/最小的子段,差的部分放在中间,所以除以二就是可能的答案。
找子段可以维护前缀和,然后找区间最大最小值就行了。
CF1519E Off by One
紫。
套路的可以想到把斜率看作点,然后把每个点能到的两个斜率相连。
然后就是构造,对于每个连通块,从一个点开始 dfs,然后除去父亲之外每个点剩下的树边以及返祖边相互配对,有剩下的和回父亲的配对,这样一定是最多剩下 1 个。
P15650 [省选联考 2026] 摩卡串
紫。
考虑什么东西是有贡献的,首先是原串的前缀,还有原串的一段前缀+一个原串为 1,新串为 0 的位置+随意。
所以可以设计一个状态 \(f_{i,j,k,0/1}\) 表示有 \(i\) 个字典序小于原串的字串,匹配到原串的第 \(j\) 位,有 \(k\) 个第二种情况的前缀,是否包含原串的最短长度。
可以使用哈希或 kmp 简单处理在匹配到某个节点时,加入一个数的贡献。
然后长度这个东西其实可以用 bfs 直接搜,记录来的状态,注意卡常。
CF555E Case of Computer Network
紫。
首先边双就是弄个环出来就可以两两可达,重点是不在边双的边。
先缩点,然后就是一棵树,树上的边只能有一种方向,可以做个树上差分,同时存在上下就无解。
P8456 「SWTR-8」地地铁铁
紫。
结论,结论,还是结论。
首先可以拆成总的减去只有黑色路径,只有白色路径以及只有纯黑纯白路径。
前两个限缩点双,然后去相连的纯色点双里跑并查集就行了。
后面的首先可以证明一定不经过割点,然后对点双内部考虑,首先分为黑白两部分,而且这两部分之间没有连边。
所以就是只有起点和终点同时有两种颜色的出边,统计一下即可。
P11695 [JRKSJ ExR] 昼寝
黑。
很神奇的一道题,让人很想写,但是你说这是人吗?
先将 \(r\) 统一 -1,那么就是求所有被 \([l,r]\) 包含的区间是否覆盖了所有位置。
首先我们考虑给出一些区间,如何判断是否存在满足条件的选取方法,不存在时间的限制。
直接扫描线,在每个点维护包含它的最大左端点,判断 \([l,r]\) 内是否有点 \(< l\) 就行了。
感觉不离线肯定没办法做,然后这种出现时间的题一般情况下是考虑类线段树分治状物,但是区间包含这个限制不好做。
所以考虑按照区间分治,然后每次处理经过中点得询问。
对于每个询问的贡献分分为两部分,一个是跨越中点的,一个是不跨越的。
对于跨越中点的部分,可以发现就是一个类似于上面的过程。
考虑按照时间枚举,每次把对应的区间插入或删除,但是这样要维护区间最值会多个 \(\log\)。
但是因为都跨过中点,所以并不存在会在中间空一块的问题。
所以直接只在端点修改就行了,撤销的时候可以预先用优先队列维护出来,直接修改即可。
以左端点为例就是在 \(l\) 处插入 \(r\),然后对每个询问线段树二分,找到最小的 \(l\) 使对应的 \(r\le qr\)。
然后就是不过中点的,因为这样的话可能就不是连续的,以左边为例。
考虑从左到右去扫,每到一个点就插左端点在这里的询问,然后对于这个以这个点为左端点的区间,右端点作为权值,对时间区间进行 chkmax。
然后在每个点修改完后,判断是否有最大右端点小于这个点的询问,拉出来更新。
P11983 [JOIST 2025] 展览会 3 / Exhibition 3
黑。
我去,终于过了,sb 超速检测。
先开桶记录每个数的出现次数,然后可以发现每个数的贡献范围就是现在存在的前若干个+后面零散的段。
前面的部分可以二分,但是正常的二分会 T,考虑先倍增找到第一个 \(k\) 使得 \(2^k\) 无法被覆盖,接下来在 \(2^{k-1}\) 到 \(2^k\) 的范围内二分就行了。
关于 check 按照超速检测去贪心就可以了,正反各做一遍,这样就可以得到每个点的可取范围。
接下来考虑加入一个区间对可取范围的影响:
-
包含一个可取区间,那么一定存在点,不用管。
-
只与一个区间有交,那么这个区间的大小就会变成和当前区间的交。
-
和两个区间有交,那么就是形如当一个区间的左/右端点满足什么条件时,另一个区间的端点要对应变化。
第三个可以用两个优先队列处理,把所有这种条件左端点限制升序,右端点限制降序,每次区间修改后暴力跑。
对于每个区间,包含它的可以按右端点排序后线段树二分去找。
关键是如何找到最小的满足 2,3 任一条件的区间,可以发现此时一定有一个端点在区间内,所以用个线段树就可以求出每个区间对应的最小可行区间。
然后扔到优先队列,每次额外判断一下,因为缩短的次数很少,所以时间复杂度是对的。
P17141 [NOI 2026] 传送
紫。
其实不是很难,注意到如果走一段再重开一定不优,所以一定是在叶子开始往上的一个连续段是传送。
观察期望的式子,可以发现一定要以终点位根,取深度大的点传送,因为同深度的贡献正负性相同,所以一个深度的点要么全选要么不选。
就可以二分,难点在于如何知道选出点的深度和。
考虑点分治,记录每个点的邻域深度的前缀和,然后在点分树上暴力跳父亲,就可以 \(\log^2\)
考虑优化,可以发现相邻点的最优取值点只会变化 1,所以可以直接求出一个点后 check。
P15651 [省选联考 2026] 夜空
黑。
偷了个懒,可能是假的。
首先考虑这个东西就类似于在一个环上不断移动分界点,移动的同时要将方向上的两个数合并。
记按照原来是数组排好后,从小到大排布方向为逆时针。
所以考虑可能的轨迹,就是先将一部分顺时针移过去,再移回来一些数,最后再将一些数再移回去。
因为最后停留的在分割点的左或右只和模 3 的余数相关,所以可以按照最后的分割点分成四段:只走一次+走两次+不走+走两次。
然后就可以 dp 了,先进行一些位移,枚举结束时候的第一个数,这里最简单的方法就是 \(f_{i,j,0/1/2/3}\) 表示序列前 \(j\) 个匹配到了所需要得到第 \(i\) 个,现在在第几个段。
然后一种方法是暴力枚举下一个位置,但是可以发现很多转移是无效的,考虑 \(j\) 可以转移到 \(l,l'\),那么有 \(l'-l \equiv 0 (\bmod 3)\) ,且中间异或和为 0。
所以可以只找后面第一个满足条件的,后面 0,1,3 就可以直接从前面的对应点转移。
对于包含原开头的部分会有一些其他限制,要特判。
这里会 tle,可以提前判掉一些一定不能包含 \(b\) 序列的情况。
构造的话可以先按照原来的 dp 数组赋每个数字属于的段,然后按照上面的流程模拟。
P17144 [NOI 2026] 木棉
黑。
首先考虑暴力,就是从小到大依次处理,从它的最后出现位置开始,找到第一个没有使用的点作为父亲,判断是否有边就对这两个分别做。
考虑记录 \(cnt\) 为没有确定父亲的编号小于 \(x\) 的数的个数,然后考虑 cnt 的变化方式。
开始的时候就是在区间内没有出现的值的个数,假设当前扫描到 \(i\),首先取最小的连在 \(i\) 上,然后如果 \(i\) 是最后一个,且 \(a_i<x\) 就 \(cnt+1\)。
所以目标就是找到第一个 \(cnt=0\) 的位置,+1 就是所求。
因为 \(cnt\) 不增,这个东西就可以二分,考虑上数据结构维护。
这里可以用树套树,外层是位置,里面用一个树状数组记录小于每个值的数的个数,这里需要离散化,然后就可以线段树二分了。
P7353 [2020-2021 集训队作业] Tom & Jerry
黑。
考虑什么情况下 Tom 会获胜,Tom 的策略一个是不断走割点缩小 Jerry 的活动范围,一个是走到一个点使得和所有 Jerry 可达的点有连边。
显然第二种情况一定是在一个点双里面的,所以先把圆方树建出来然后 dp。
\(f_u\) 表示 \(u\) 子树内是否能抓到,\(g_u\) 表示子树外,那么转移的时候就是看子树内有没有不符合条件的点。
P12077 [OOI 2025] Strong Connectivity Strikes Back
黑。
首先缩点弄成 DAG,考虑一条边可以删掉的条件就是如果将它反向就会形成环,就是存在另一条 \(u->v\) 的路径。
因为可能有重边,如果要保留其中一条记得乘上方案。
然后对每个 scc 分别考虑,首先如果去掉一条边,整个图还是强连通,那么就不能删。
如果变化,那么必然是分裂成了若干 scc,按照分开的状态分组,相同状态所删去的边一定在缩点后是一个环的一部分。
所以如果是整个环,那么要保留一个,否则可以全删。
CF730K Roads Orientation Problem
黑。
双极定向板子,考虑先从 s 出发 dfs 出一颗树,然后先按照深度定向。
但是这样对于不在 \(s\) 到 \(t\) 链上的部分的定向是不对的,考虑从 t 开始 bfs 修正。
假设当前考虑到树边 \((u,x)\),令 \(u\) 为 \(x\) 的父亲,对于一条返祖边 \((u,v)\),这里记 \(dep_u<dep_v\),如果 \(v\) 没有在之前被处理到,那么就需要调整。
一种可行的构造就是让 \((u,v)\) 和 \((u,x)\) 方向一致,将 \(v\) 到 \(u,x\) 所在链的部分全部反向,然后将 \(v\) 加入队列,\(x\) 不断跳父亲。
这样的话每次定向的部分就类似于一个耳,并且因为 \(v\) 和 \((u,x)\) 链的交点深度不小于 \(x\) ,必然不存在环,且只有 \(u\) 的入度为 0,在跳父亲的时候可以补全。
至于无解判断,可以直接加上一条边 \((s,t)\) 判断点双数量。
P11194 [COTS 2021] 县 Županije
黑。
10 个 dfs 是人吗?首先观察发现,如果两个点相邻且颜色不同,那么他们到县城的距离必然相同,否则就是无解或者可以将一个变色。
所以考虑 \(f_u=0/1\) 表示是否能作为县城,考虑转移,可以从下往上推,每个同色连通块内满足所有下方连通块限制的点就是 1。
这里有一个 \(n^2\) 的做法,对每个 1 向他的父亲连通块的对应距离贡献,最后符合的条件数恰好为相邻颜色数的就可以。
可以发现就是一个类似于树上圆的东西,考虑对每个块点分治去算共享,就可以 \(log\) 了,构造倒推即可。
P5311 [Ynoi2011] 成都七中
黑。
比较是题,考虑点分治,可以发现必有一个分治中心可以包含整个 \(x\) 所在的连通块,考虑 \(x\) 和分治中心连通的条件就是路上的点都在 \(l,r\) 范围内。
对于所有需要求解的询问拉出来排序扫描线,考虑每个点的贡献,每个颜色一定要挂在最靠右的左端点,所以扫的时候可以令开一个同桶,树状数组维护。
P10805 [CEOI 2024] 加油站
黑。
点分治每次处理跨过分治中心的路径。路径分为两部分,向上的部分可以二分找到最远的距离不超过 \(k\) 的祖先 \(x\),那么上一次在 \(u\) 处加油的就会到 \(x\) 处。
向下的部分因为路径发散,难以二分,考虑对于一个节点 \(u\),如果一条路径能走到 \(fa\) 却走不到 \(u\),那么就会对 \(fa\) 有贡献,可以树状数组维护。
P7126 [Ynoi2008] rdCcot
黑。
有一个性质,就是按照 bfs 序排序,那么如果 \(bfn_i<bfn_j<bfn_k\) 且 \(dis(i,k)<c,dis(j,k)<c\) 有 \(dis(i,j)<c\)。
所以就有答案为 \([l,r]\) 中按 bfs 序排序,在前面没有连边的点数。
可以求出来每个点有连边的比它小的最大值 \(pre\) 和比它大的最小值 \(nxt\),然后就是矩形加单点查,可以扫描线。
对于 \(pre\) 和 \(nxt\),考虑点分治,用一个线段树记录区间 bfs 序 min,然后就可以线段树二分了。
因为子树内的点到当前点的距离一定不会超过深度和,所以不需要去掉子树内贡献。
P10574 [JRKSJ R8] 暴风雪
黑。
又来一个不是题的。
考虑到就是一段树链的 chkmax,可以发现这个值变化的点只有 \(O(\sqrt n)\) 级别。
考虑重剖,对于轻边可以直接用树状数组大力维护,重边考虑开 vector 记录每个深度的轻子树的和,然后就可以直接查。
但是因为要找第一个深度超过 \(u\) 的,暴力的方式是直接记,但是空间不够,考虑对前 \(B\) 个暴力跳,剩下的部分对每个记轻子树深度超过 \(B\) 的祖先,这样发复杂度就对了。
考虑线段树去维护和,但是因为每个都要做,就会带 \(\log\)。
有一个 trick 就是发现区间不交,可以直接将询问一起更新掉,复杂度就是对的。
CF1483F Exam
黑。
说是 AC 自动机板子,但我显然不会 AC 自动机,遂补习。
如何计算匹配到一个点的次数,就是先暴力匹配,然后在每个点打标记,匹配上的数量就是 fail 树上的子树和。
首先考虑以每个点作为右端点去匹配,显然只有匹配成功的最长串是有用的,将这些串的位置和长度记录下来。
然后可以发现这些区间中,如果一个区间被包含,那么它一定是没有贡献的。
所以我们考虑记录每个串的未被包含的出现次数,和他的总出现次数进行比较,相同的就有贡献。
总次数用树状数组维护。

浙公网安备 33010602011771号