8.2 - 8.30
-
2025/8/29
CF1921G
学习了本题求三角形前缀和的方式,对于四种方向,将矩阵旋转再处理。代码很长,要注意很多细节问题。
D15 B
思考了 \(30\) 分钟。
想到只有相同的字母才能换,所以同一下标出现的不同位置之间都是一样的字母。
有个变量类型写成
char
了,看了好久没看出来。 -
2025/8/28
CF1933G
\(n、m\) 都很大,所以一定有规律。观察到两个样例里空矩阵的答案都是 \(8\),所以可以知道空矩阵答案就是 \(8\),且所有答案不会超过 \(8\)。
可以推出来合法的矩阵是由 \(aa\) 和 \(bb\) 交错排的。再来分析 \(8\) 的构成,其中一个 \(2\) 是 \(ab\) 可以互换,第二个 \(2\) 是横纵可以互换。
最后一个 \(2\),发现 \(m\) 为奇数时,最后会多出一列,所以最后三列的方案会有一个 \(2\)。
只用在每一次定下一个位置的时候看跟合法方案矛不矛盾即可。
CF1921
A,3 min;B,5 min;C,10 min。
D,11 min;E,46 min;F,54 min,其实又有初始化的问题。
G,目前还不知道三角形前缀和怎么求。
-
2025/8/27
CF1933
A,1 min;B,6 min;C,14 min;D,11 min。
E,53 min。二分大于 \(u+1\) 的第一段 \(x\),如果这一段大于 \(0\) 就保留,否则不保留。
最后的问题是没有注意到如果 \(x\) 不被保留,\(x\) 之前的一段贡献可能为 \(0\)。但我觉得只有可能是当当前段结尾及之前恰好有 \(u+1\) 个数,并且这一段长度为 \(1\),前面那一段才会是 \(0\)。
但是这么特判是错的,而按之前的计算方法算 \(x\) 前一段是否为 \(0\) 就对了。
F,39 min,一定要看到题面中说的最后一列没有石头。因为石头太多不好移动,移动是相对的,所以看成机器人和终点每次操作都要向下一格。
-
2025/8/26
CF1955H
一定要注意到每个防御塔在 \(r\) 确定后的贡献是确定的。所以可以处理出一个二维数组,这样问题就与地图无关了。
因为每个 \(r\) 只能用一次,相当于不能选同一列的数。发现 \(r\) 不可能到 \(50\),因为敌人的生命值是按 \(3\) 的幂增长的,所以 \(r\) 反而很小。可以状压 \(dp\) 处理。
CF1941
A,1 min;B,4 min,少判了倒数第二个数;C,11 min,一开始思维混沌。
D,18 min;E,53 min,记录的具体数值,用
multiset
和queue
超时。后面改成记录下标,再用单调队列处理。F,38 min;G,26 min,超时,
fill
范围太大了。 -
2025/8/25
CF1955
A,2 min;B,13 min;C,15 min。
D,10 min,注意又是初始化太慢的问题;E,23 min,一开始莫名想到二分,发现无法二分就开始枚举了。
F,27 min;G,32 min,写的
BFS
,在加入状态后判断合不合法,会MLE
,其实也可能是一开始没有判重复经过的点,老是忘记判。 -
2025/8/24
D14 H
回顾了二分图。还要加强练习。
CF1974
A,8 min,有些小细节写错了;B,7 min;C,10 min;D,23 min。
E,40 min,注意每一天不是只能买幸福或赚钱,两者都可以做。注意
long long
的问题,还有初始化时不能直接fill
全部,会超时,每次只赋值可能需要用的。这些问题调了 \(10\) 分钟。F,40 min,边界处理要注意。还要注意,从
sy
里取坐标,是按先 \(y\) 后 \(x\) 存的。G,17 min,反悔贪心。
-
2025/8/14
CF1980
A,2 min;B,8 min;C,23 min。
D,35 min,最开始对于删第一个和最后一个的处理有问题。
E,20 min;F1,60 min,注意要开
long long
。F2
如果从一个方向考虑需要用到单调栈,需要回退,那么从另一个方向考虑也许可以直接顺着找到答案。
\(F1\) 是先排行再处理列,遇到更左边的拐点就往前移。然而先排列再处理行可以线性的确定所有拐点。
对于删掉一点,相当于把它前后两个拐点之间的部分重新算一遍,就在之前排序好了的基础上再计算就可以了。
G
暴力是枚举 \(u\),处理出根节点到每个点的异或和。注意是异或,所以不存在要找最近公共祖先。
不枚举 \(u\),就用
01trie
找到跟 \(d_v\) 异或 \(x\) 异或起来最大的 \(d_u\)。有可能找到自己,处理方法是把自己删了再找,算完之后再加回去。
对于修改,是对所有边修改,容易发现偶数次修改 \(y\) 会抵消,奇数次会多异或一个 \(y\)。
如果 \(u、v\) 的深度的奇偶性不同,就要多异或,否则答案不变。如果拿着多异或 \(y\) 的数去找,就是希望找到不同层的点。
奇数层找偶数层,偶数层找奇数层。处理它很普遍的方法是,分奇偶性建两个
01trie
。用多异或 \(y\)找,就在不同层的那棵里找,否则在同层的这棵里找。这些技巧都很基础,都要记牢。
-
2025/8/13
CF1986
A,2 min;B,10 min,只用按顺序模拟一遍就行了,一开始没有注意到之后的操作绝对不会在更前的位置。
C,25 min,题有点小绕,理解了一会,贪心即可;D,35 min,忘了 \(n^2\) 可以,所以在想贪心,写了一段时间没写对。
E,45 min,\(n\) 为奇数,计算答案的时候没有想清楚,写了个前后缀,浪费了点时间。
F,数据范围看错了,写了 \(n^2\)。想到肯定是找桥,减少的点对是两边点数的乘积。但是对
tarjan
算法不熟悉。不过也可以不用
tarjan
。看到无向图要能联想到建生成树,生成树上就只会有树边和返祖边,返祖边连成的环上的边都不会是桥,所以树上差分后找到被累加 \(0\) 次的边就是桥。G,可以想到 \(n^2\) 暴力,重要的是继续从整除想到约分。
所以每个 \(p\) 会形成两个具有对应关系的数,然后又通过倍数关系,产生一些四元环,要求四元环个数。
可以枚举三条边,从而确定另一个点。一般可以用折半搜索优化。
-
2025/8/12
CF2094H
CF2037
A,2 min;B,7 min,一开始没看懂题;C,7 min,忽略了
4+5=9
。D,30 min,没看清题目最小化的是次数;E,40 min。
F
需要熟悉这类型题的优化过程。首先从暴力做法开始,枚举次数,枚举位置 \(p\),枚举每个怪物校验是否能被杀死。
发现知道位置后,可以知道每个怪物几次能被杀死。取前 \(k\) 个少的杀,就能直接知道最小次数。但位置范围太大了,要考虑进一步优化。
而知道次数和怪物,可以算出有哪段位置可以让当前怪物死。所以变成枚举次数、怪物,计算出一段可行的段。最后统计是否有被覆盖 \(k\) 次的点。
对于是否被覆盖 \(k\) 次,用扫描线校验。也可以差分,需要离散化。
最后次数具有单调性,二分处理即可。
所以遇到范围大的、不能枚举的东西,要想办法通过其他的信息求,或者找单调性等。
实现的时候数组开小了。
G
非常重要的是,注意到 \(i<j\) 才有可能有有向边,要想到它跟最长上升子序列本质一样,只是转移条件变成 \(gcd \neq 1\)。
问题就是没有想到。
所以首先能写出 \(n^2 dp\)。由记录以 \(i\) 结尾的最长长度 \(l_i\),想到本题可以记录以 \(i\) 倍数结尾的最长长度 \(l_i\)。
记住看到判断两个数是否互质,第一反应不能是枚举因数,而是质因数,这样需要枚举的部分也会大幅减小。
所以最后的转移就是枚举质因数,取最大值更新当前答案,再把答案返回去。
注意这样算出来的方案数会有重复部分,需要容斥处理。
-
2025/8/11
D17 F
思考了 \(40\) 分钟。
可以使用启发式合并。处理儿子之前记得先把父亲加进
set
。D13 A
思考了 \(20\) 分钟。
每组都会选两条较长的边,根据边的大小关系看有多少种情况。实现没有什么困难。
D13 B
思考了 \(20\) 分钟。
想到容斥。注意在算 \(ab\) 都有序的时候,要先判断是否有两个都有序的情况。
CF2094
A 2 min;B 3 min;C 5 min;D 10 min;E 24 min。
F 28 min,一开始还以为是斜着放,但如果 \(k \gt m\) 就不行;G 20 min。
H。。
-
2025/8/10
A,2h+,60(60)
就是不会填 \(2\) 的方案。下次绝对先把会写的写了,用剩的时间再想要思考的部分,不能赌自己会写。
B,15 min,60(60)
其实知道这题的性质,也想到用单调栈。但是时间不多了,第一眼没有很清晰的思路,以为不会写。当时想二分只会暴力更新最小值数组,也不会写 \(st\) 表。就直接写了暴力。
居然现在还不会 \(st\) 表。
C,35 min,45(45)
第四档的状态不应该没想出来,主要是没注意到不用具体地知道两堆各自的和。
只需要知道差值。所以 \(d_{i,j}\) 是考虑到第 \(i\) 个,两堆差值是 \(j\) 的最小总和,总和偏移一下就行了。
D,10 min,0(0)
看了感觉一时半会写不出来。\(n^2 dp\) 要会写。
E,20 min,0(0)
不知道怎么把填数的具体方案弄出来。但这个暴力枚举边再校验有 \(32\) 分,不需要知道方案啊,也不知道当时为什么会想知道具体方案。
F,30 min,0(0)
尝试 \(m=n-1\),错了。它是一棵树,非常不应该,虽然也许是我把它想成了一条链吧。
第一档 \(01\) 字典树。要多加巩固,不然太不熟了。
-
2025/8/9
D18 B
才发现昨天做错题了。思考了 \(30\) 分钟。这题观察到树会是一条链,所以随意枚举一条边两端的颜色就可以推出所有颜色。实现没有什么问题。
D18 C
思考了 \(30\) 分钟。想到每次加一个点只要把答案用已有黑点到当前点的最短距离更新即可,然后再以它为起点更新其他点的 \(d\),也就是距离黑点的最短距离。
实现的时候有一点细节没注意,比方说 \(ans\) 的初始值不能跟 \(d\) 一样。
-
2025/8/8
D19 A
思考了 \(20\) 分钟,发现 \(x_i\) 和 \(x_{i+1}\) 有 \(x_{i+1}-p_{i+1}+1 \leq x_i \leq x_{i+1}\) 的关系。
筛出一遍所有数的最大质因数,再在范围内枚举 \(x_1\),计算出 \(x_0\) 最小值即可。
实现没有什么困难。
D19 B
思考了 \(40\) 分钟,把式子中的 \(lcm\) 转化成 \(gcd\)。
然后通过一堆需要整除的限制,枚举因数,就可以算出 \(i*j\),其中 \(i*gcd(a,b)=a,j*gcd(a,b)=b\)。
过程中在表示出 \(gcd\) 后没有想到进一步转化,再引进一个变量表示 \(c*i*j-d\),再表示出 \(i*j\)。
预处理 \(i*j\) 的质因数个数就可以算出有多少个 \(i、j\) 组合,也就是 \(a、b\) 组合。
实现比较顺利。
D19 C
想了 \(40\) 分钟。想到数被分成几组,组之内互不干扰,处理出每组的信息再相乘。
思考到对于一组,能选的方案数可以用 \(dp\) 算出来,并且可以预处理。因为方案数跟具体数值没关系,只跟数列长度有关。
只需要再知道每个长度对应的数列有多少个即可。
不太会处理数列个数。实际上长度至少为 \(i\) 的数列的个数就是能被 \(k^{i-1}\) 整除的数的个数。
D18 A
思考了 \(10\) 分钟,想到父亲和儿子的权值要尽可能接近,所以按 \(dfs\) 序赋值即可。
D18 B
思考了 \(25\) 分钟,第一反应是先让 \(a、b\) 会合。\(a\) 到 \(b\) 的路径上的中点就是会合的地方。
然后每条边会经过两次,每次要返回根节点,为了答案最小,就找一条最长的最后走,就不用往回走了。
实现过程中,对如果 \(a\) 到 \(b\) 的路径长是奇数怎么确定会合点有点问题。
-
2025/8/7
A,30 min,50(50)
每次正着加数,\(nlogn\) 算最长上升子序列。感觉不会正解就没写了。
考虑倒着删数,如果删的数不在当前最长上升子序列上,答案就不会变,否则再重新算一遍。
实现上每个数多记录一个前驱用来还原序列即可。
B,70 min,30(40)
先写了 \(n^2\) 暴力,后面思考第一档用了一定时间,给的样例都过了,但是没分。
C,80 min,5(35)
写了前三档 \(35\) 分的部分,只有 \(b=0\) 有分。赛时认为 \(a=0\) 的答案是 \(C^{z-1}_{b+z-1}\),其中 \(z\) 是相同字符连续段个数。\(a=b=1\),认为操作结果不会重复,但是输出是答案的两倍,加上没有样例可以测试,就草草除二了。
D,35 min,10(10)
搜索,没有继续思考。应该写出 \(n^2\) 树形 \(dp\)。
赛时树形 \(dp\) 的实现卡在不知道怎么处理覆盖的点会重复的问题。
-
2025/8/6
D17 A
思考了 \(25\) 分钟。
想到因为旅游城市不能产生贡献,工业城市可以产生贡献,所以旅游城市要放在工业城市前面,让尽可能多的工业城市经过旅游城市。
那肯定有一些节点来作为工业城市和旅游城市的分界,对于分解节点 \(i\),子树 \(i\) 里面除了 \(i\) 都是工业城市,\(i\) 往上直到根节点都是旅游城市。
在取 \(k\) 个较优的节点作为工业区有点问题,主要是不知道正确的贪心方式。
实际上是选 \(deep_x-sz_x\) 大的节点。
先假设全都是旅游城市,肯定是从叶子节点往上变。如果一个节点从旅游城市变成了工业城市,这个时候它的子树里应该都是工业城市。
考虑多的贡献和损失。当前节点会新产生贡献,它可以向上走到 \(deep_x-1\) 个旅游城市;其子树内的每个点都相当于少走了当前节点这个原本的旅游节点,总贡献减 \(sz_x-1\)。
所以把节点 \(x\) 由旅游城市变成工业城市产生 \(deep_x-1-(sz_x-1)\) 的贡献。
D17 B
思考了 \(30\) 分钟。
想到要选在中心的点当作核心城市,只用考虑它们顺着当前方向走到的最远点。如果从核心城市 \(x\) 走到非核心城市 \(y\) ,经过了别的核心城市,那么这个 \(y\) 的距离与 \(x\) 无关。
这就解决了第一层“最小”,非核心城市到任意一个核心城市的最短距离。
所以中间的这 \(k\) 个点形成的类似于一个圈的东西,它越大就会使别的点到这个圈的距离越小。所以就在想是不是可以空几层再放一圈,然后发现忘记了这 \(k\) 个点要都在一块。
并且从中心扩张的时候,往到最远点更长的点扩,因为最终答案是最小的最大值。
接下来就是找到这 \(k\) 个点应该在哪,也就是找尽量中心的位置。在这里卡住了。
中心位置其实是树直径的中点。直径是最长的一条路径,从它的中点往外扩张,能尽可能让其他点到这个圈的最大距离变小。
这是第三层“最小”,保证整体都小。
所以从树直径中点往外扩。找到到最远点距离最大的前 \(k\) 个点变成核心城市就可以了,它们肯定是连在一起的。
答案在其他的点取
max
,就是第二层“最大”。实现了 \(30\) 多分钟,注意在算答案的时候,非核心城市跟核心圈还缺一条边,记得加 \(1\)。
D17 C
想了 \(30\) 分钟。想到树形 \(dp\),根据数据范围,也许需要换根 \(dp\)。\(d_{i,j}\) 表示 \(i\) 子树中距离为 \(j\) 的答案和。
并且,只要是跳跃距离 \(\leq k\),就一步到;否则不能,那么每步都要尽可能大,都跳满 \(k\)。
实现的时候没搞清楚转移的实际含义,不是从距离 \(a\) 是 \(b\) 的位置 \(c\) 的 \(d_{c,?}\) 转移过来,是从 \(d_{c,b-1}\) 转移而来,其中 \(c\) 是 \(a\) 的一个儿子。
对于 \(d_{i,0}\) 的转移,要单独考虑。距离 \(\leq k\),这些点贡献为 \(1\);否则,不能一步到位,所以先跳满 \(k\),加上距离为 \(k\) 的答案。
这些点转移的共同点是都有必要的一步,要把这些一步提出来看,也就是 \(sz_j\) 步。
换根 \(dp\) 就是考虑父亲对儿子在换根后多产生的贡献,把儿子在父亲那里的贡献减掉,再把父亲的贡献加到儿子里。要加强熟练度。
注意最后答案要除以 \(2\)。实现得有点久。
-
2025/8/5
D15 A
想了 \(30\) 分钟,看到最小化最大值想到二分,判环用拓扑排序。
一直在第七个点 \(WA\),调了好久。结果是 \(k\) 没开
long long
。所以看到错较后的点第一反应就要是爆int
。D14 D
是真的不理解为什么错了。没招。确实发现有数组开小了,但开大了之后开始 \(T\)。并且在把初始化从用
fill
改成直接遍历之后甚至开始 \(WA\),这个改动是没有影响的,错了应该是别的问题。好吧其实这题不需要
long long
,改掉之后就过了。所以不能乱开long long
。 -
2025/8/4
A,140 min,60(60)
非常不好,想不出来。第一眼想到组合数学,知道是算 \(\sum_{j=0}^{a_i} C^{j}_{a_i}*{v_i}^j\),只是不会在不枚举 \(j\) 的情况下算。
想正解一个多小时未果,穿插着去写 \(60\) 分。然而在写转移的时候一直没注意总方案数要累乘。
没写出来纯粹因为不知道二项式定理:\((A+B)^n=\sum_{j=0}^{n} C^{j}_{n}*{A}^j*{B}^{n-j}\)。
\(n=a_i,A=v_i,B=1\)。
B,20 min,20(40)
少判了
n/i==i
只用进去搜 \(1\) 次,非常不好,少了 \(20\),早知道直接 \(1\) 到 \(n\) 枚举。其实不应该写搜索,应该写 \(dp\)。
C,25 min,25(25)
没有进一步想,主要去想第一题了,导致后几档没机会写。
存在做题策略的问题,对于短时间内没有任何关键思路的题,要果断选择从暴力开始写。避免出现因为某一题想正解太久以至没时间写其他部分分的情况。
后面部分分也是 \(dp\),把问题看作全都是 \(a\),选出 \(b-a\) 较大值,相当于把部分 \(a\) 变成 \(b\)。
D,40 min,20(20)
没有进一步想。最后犹豫了是做第一题还是想这题,但是因为一下子没想出来怎么判断当前边是否唯一,就觉得也许想第一题更有性价比。
-
2025/8/3
A
第 \(1、n\) 个数只出现一次,第 \(2、n-1\) 个数只出现两次,剩下的出现三次。按出现次数确定前两位,就可以依次确定其他位置。
B
最坏情况就是前 \(d_i\) 优的路都走不了,相当于
Dijkstra
的过程中只走第 \(d_i+1\) 优的。一个起点,多个终点,正着做不知道哪条路优,所以考虑从终点同时反着做。
C
因为可能有别的路径比直接走要短,并且 \(m\) 很小,所以先
Floyd
算出两个字母之间转换的最小代价。可以前缀和优化将原串的某个子串全变成某个字母的部分,即处理出 \(z_{c,i}\) 表示把 \(s_1\) 到 \(s_i\) 全变成 \(c\) 的最小代价。
考虑 \(dp\) 的优化,把转移式子拆开,分成与当前状态和上一个状态有关的两部分,用前缀最小值优化上一个状态有关部分。
D
求最大值和次大值的和,要想到先固定最大值,再找次大值的策略。
既然固定了一条边,就固定了四个点,继而想到预处理起点 \(1\) 和终点 \(n\) 到每个点的路径信息。
也就是最大边权最小值,使得可以在计算答案的时候快速得到次长边。用
Dijkstra
实现。注意找到的次大边不一定比最大边小,要判断,否则不统计进答案。最短路求的是最大边权最小值,如果最小值都不小于最长边,就不可能有这条边作为最长边的情况。
-
2025/8/2
A,90 min,100(100)
第一眼认为是二分,但发现并不满足单调性。箱子大小变小,可能会使大物品放不下,从而放下更多小物品,使得更容易满足条件。例如题面样例第三组,\(99\) 可行但是 \(100\) 不可行。
所以想到枚举箱子大小,从 \(1\) 枚举到物品大小总和 \(sum\)。有些大小没必要枚举,于是缩减到从 \(sum/k\) 到 \(r\)。\(r\) 是把 \(v\) 从小到大排序,尽量均匀地切成 \(k\) 份,最右端那份的和。
但右端点更大也无所谓,毕竟找到合法的就会
break
。对于校验,第一遍写得很暴力,硬找,后面改成
set
二分找最大值。但我觉得程序太慢了,过不了大样例,就在想能不能不枚举。没想出来,消耗了一定时间。
B,75 min,45(45)
感觉像 \(dp\),一看数据范围发现只有两档能 \(dp\),就先写了。对于第 \(5\) 档,直接判断即可。第 \(2\) 档,根据头尾两个字符的种类分类讨论。
从第二档到三四档的思路没有难度,区别就是不止一个问号段了,不应该没写出来。第三档,相当于问号段两端都是 \(0\),如果这段里面有 \(1\),就产生 \(2\) 的贡献。没有,则不产生贡献。所以从填 \(0\) 来看,先填较短段贡献更小。三四档完全一样。
没有限制的情况也就是问号段两端字符情况有三种。\(01、10\) 无论怎么填贡献都是 \(1\)。如果考虑填 \(0\),肯定优先 \(00\),多的再补在 \(11\)。
考场上因为 \(T1\) 耗费太多时间,加上排行榜,感到很有压力,比较慌乱,思路就不清晰。这题应该要写出来的。
C,45 min,0(0)
看到求能到达的点数,就要想到并查集,求连通块大小。
第一档暴力,把能走的边弄出来,加进并查集,就可以了。居然写搜索,这一档肯定要拿。
\(k\) 是 \(2\) 的次幂,就是说边权跟 \(d\) 的前几位要完全相同。把边按前面的位分组,每个组之间没有关联,每个 \(d\) 也只会跟一组有关系。然后并查集做。
考场上没有把 \(d\) 隔离开来看,包括没想到并查集,所以完全没什么思路。每次 \(d\) 都不一样,肯定不是都要从头来,而是可以统一处理一些东西,用 \(d\) 索引出来。
\(50\) 分属于范围内。
D,30 min,0(20)
第一档直接暴力插,类似于
Dijkstra
。我应该是没判重复状态。第二档,操作就只跟 \(AB\) 个数有关系。