寒假 6 日游
总结了寒假 \(6\) 天考试的题解与反思,反思是为了避免更多的错误与挂分,题解是为了复习曾经的题目与各种 trick。
Day 1
T1 game
先写了暴力,然后打表找规律,发现答案是如:\(1,1,3,1,3,5,7....\) 的,所以有理由推测是从 \(1\) 开始的等差数列,项数依次为 \(2^i\),预处理以下二分出答案在第几个等差数列然后直接计算即可。
- 考场 \(100\),感觉是道找规律的好题,锻炼了我先写暴力然后打表找规律的能力。
T2 seq
yyb 讲了一个 trick,求某个东西计数结果的平方等价于将这个东西自己与自己匹配。
那么这道题就变成了,将 \(S\) 复制一份变成 \(S1\) 和 \(S2\),求解 \(S1\) 和 \(S2\) 能够匹配上的子序列的对数。设 \(f_{i,j,k}\) 表示 \(S1\) 匹配到了 \(i\),\(S2\) 匹配到了 \(j\),已经匹配了 \(k\) 的子序列。
- 考场 \(35\),时间没有完全利用好,很多人这题的分都比我高,我只写了 \(k=1\) 和特殊性质 A(还写挂了),还是需要合理分配时间,不要看到 dp 题目就畏惧。
T3 carrot
带修 dp,发现可以矩阵辅助转移,所以可以考虑区间矩阵乘法,然后这玩意可以用平衡树维护(因为编号会变化,所以用平衡树记录相对位置)。
- 考场 \(30\),拿到了该拿到的分,唯一不足的点是读题花了很长时间,有一点畏惧的心理。
T4 path
这题考场做的就比较开放,直接写了暴力和所有的优化,惊奇发现过了大样例,然后就跟 \(50\) dp 同分了,但其实本来有 \(60\),忽略了一个小细节就挂了。
轮廓线 dp,感觉很开阔思维,把状态设为轮廓线,如果需要转移就将轮廓线改变即可,轮廓线为限制答案的下限,从来没有接触过这种 dp 类型。
- 考场 \(50\),感觉正解让人眼前一亮的感觉,十分的巧妙。
Day 2
T1 move
需要发现一个性质,沿着数轴从左往右看,任何一个点的相对位置排名是一定不会发生变化的。
那么我们只需要关心每个时刻的位置而不需要知道编号,我们有可以发现一个性质,两个点碰撞在不关心编号的情况下相当于穿过了对方,那么只要单次二分即可。
- 考场 \(0\),是一个非常大的失误,脑抽了,中间一个变量忘记将 \(\text{double}\) 转 \(\text{int}\) 了,丢了 \(40\),没有自己造小数据和对拍。
T2 group
考场上太急躁,看错题了,导致写了错误的 dp 并调了很久。
首先对于 \(a_i\) 排序,那么对于每个新进来的 \(a_i\),要么加入某个划分的集合,要么新建立一个集合。这两件事情继续划分,则加入到某个集合,并且作为集合的最大值;加入到某个集合,不作为集合的最大值;新建立一个集合,并作为集合的最大值;新建立一个集合,并不作为集合的最大值。
设 \(f_{i,j,k}\) 表示当前填到了第 \(i\) 个数,目前还有 \(j\) 个组没有填入最大值。转移的时候考虑 \(a_i \sim a_{i-1}\) 到几个集合中就好了。因为当前数不是这些集合的最大值,因此这些集合的最大值一定不会小于 \(a_i\) ,所以可以把这部分到最大值之前的差值先加进来,等到结束的时候再停止给这个集合累加就好了。
- 考场 \(0\),因为来不及写暴力了,这是错误的做法,应该先将题目看清,手玩一下样例再去仔细思考,可以一边写暴力一边想。
T3 production
建正图与反图,直接跑 \(\text{dijkstra}\) 即可。
- 考场 \(100\),还是该拿的分拿到了。
T4 coloration
设 \(f_{i,j}\) 表示在以 \(i\) 为根节点的子树内,已经将 \(j\) 个点染成黑色时的最大收益。
向上转移的时候,需要先将子树内的收益直接加起来,然后再加上当前边要被计算的次数,这个值可以通过子树内的染色情况得出,复杂度实际是 \(O(nm)\) 的,只要枚举子树时不枚举超过子树大小即可。
- 考场 \(30\),暴力分拿稳了。
Day 3
T1 geronimo
因为将一个过程看成连边的话,可以发现每个点入度出度均为 \(1\),所以必然成为一个环,所有位置的环的 \(\texttt{lcm}\) 则为整个序列的循环节。
- 考场 \(30\),打的是暴力,正解已经想到了却没有想明白该怎么求循环节。
T2 allonsy
可以枚举往右走 \(i\) 步,那么往左走了 \((n-i)\) 步。此时由于往右走的概率为 \(q\),左的概率为 \((1-q)\),左右步数分好的情况下又有 \(n \choose i\) 种可能性,所以对于枚举的 \(i\),概率为 \({n \choose i }\times q^i \times (1-q)^{n-i}\),之后直接算期望即可。
- 考场 \(0\),认为左右步数无论怎么排列都是一样的结果(即没乘组合数),惨挂 \(100\)。
T3 good
CF438D 加强版,又是一道打表找规律的题目。
首先考虑好数有什么性质,先暴力打表,发现大部分都是质数,猜测后将质数去除,发现还有 \(2\) 的整次幂与 \(6\),那么其余操作可以线段数维护,好数可以预处理(因为数字 \(1\leq x\leq 10^6\))。
根据 CF438D 的 trick 可以得出,线段树区间取模时记录最大值,如果当前区间最大值小于 \(\bmod\) 则不递归,可以证明其复杂度为 \(O(\log V)\) 的。
- 考场 \(70\),忘记了这个 trick,直接暴力下传 \(\bmod\) 导致复杂度不正确。
T4 color
现在只懂了时间、空间复杂度错误但能过的解法。
map 暴力存出在 dfs 过程中的所有颜色点的数量,在上传时将父亲 map 全部加上儿子的 map。
- 考场 \(30\),是最朴素的暴力。感觉 yyb 说的很对,既然别人能暴力高分或满分,你又为什么不能优化你的暴力进而拿高分呢。
Day 4
T1 travel
首先可以很容易的暴力 dp,发现可以写成矩阵的形式,进而观察数据范围发现可以矩阵快速幂优化,因为除了时间其余数据范围都很小。
- 考场 \(0\),是最惋惜,如果这题随便打一个分层图或者暴力 dp 就会得 \(50\),然后就 \(300\) 了。还是一定一定要对拍,自己手造数据!!!
T2 army
拆式子或者按照方差定义推测。
性质 \(1\):新加一个数不会将方差变小。方差指的是数据的分散情况,所以新加一个数要么使平均数不变,要么改变平均数,造成数据波动(即方差变大)。
性质 \(2\):一定取排序后相邻的一段为最优。因为方差指的是数据的分散情况,所以排序后越分散就会方差越大,既然方差要求最小,就需要将相邻数据波动将到最小,即排序后连续的一段。
那么此题做法就很简单了,首先人数根据性质 \(1\) 默认取 \(l\) 最优,再从小到大排序,用类似于滑动窗口一样的东西模拟(性质 \(2\)),记得方差改变的东西可以存下来,不需要每次滑动时都 \(O(n)\) 算。
- 考场 \(100\),此题比较好,锻炼了推式子的能力也锻炼了猜结论的能力。
T3 ned
维护到 \(i-1\) 为止的后缀 \(\gcd\),可以发现性质:无论如何,添加一个数,仅会将所有的后缀 \(\gcd\) 不变或减少,且至少减少两倍,所以容易推出后缀 \(\gcd\) 不同的数量至多 \(\log V\) 个。容易得出,先算一遍,保存每一段的位置,再次算到时利用快速幂跳过后缀 \(\gcd\) 相同的这一段,时间复杂度 \(O(n\log V)\)。
- 考场 \(100\),挖掘出性质就十分容易做题了。
T4 snow
先可以求出树的 dfs 序,显然对于一颗子树就变成了序列上的一个区间,那么可以用线段树,维护一个区间表示的点的直径,对于两个区间,直径的合并就是从四个端点中任选两个连成的路径,选出其中长度最长的,即为合并后的直径。
- 考场 \(50\),暴力分。
Day 5
T1 camera
对于每一个点,可以算出它穿过给定矩阵的时间区间,注意可能永远到达不了。对于这些时间区间,可以拍平到一个时间段,显然每个时间段的左端点是最优的,在右端点序列上二分有几个右端点小于当前的左端点,继而可以算出选这个左端点带来的贡献,最后贡献取最大即可。
- 考场 \(40\),幸好听取了 yyb 的建议挂了暴力,否则直接挂成 \(0\) 了。我的代码的错误也是不可原谅的,时间段排序应该按左端点从小到大,这样才能保证枚举的连续性,结果当时脑抽写反了,写了暴力依然没有写对拍也没有自己造数据,是在是惋惜!
T2 bg
贪心,从左往右扫值域,在 \(l_i\) 处把管理员 \(i\) 插入堆中,在 \(r_i\) 处把管理员从堆中丢弃。对于一个毒瘤度为 \(a_i\) 的题目,在扫到 \(a_i\) 的值域的时候直接将其和剩下的所有管理员中,\(r_i\) 最小的那个匹配即可。
- 考场 \(10\) 分,暴力挂错了,这实在是垃圾问题。
T3 firelead
这么简单一道题目没看出来我属实脑瘫。
将所有的叶子节点为起点,同时跑 \(\text{dijkstra}\) 即可。
- 考场 \(50\) 分,写 \(60\) 暴力还挂了。
T4 hopetree
也是一道脑瘫题。
找到一个中间点,这个点到其余 \(2\) 个点的距离相同。那么以这个中间点为根节点,这三个点一定是不同的三棵子树中的深度相同的点,做一个 dp 即可。
- 考场 \(60\) 分,用的是 \(\text{bitset}\) 优化暴力。考场上这个行为十分危险,本来此题用 \(\text{bitset}\) 是为了节省空间,当时算的是 \(200 MB\),结果发现我
#define int long long应该还要有个 \(2\),所以总共为 \(400 MB\),差点全爆。所以还是要检查自己的代码,利用 linux 命令行检查一下自己的空间。
Day 6
T1 联合权值
直接树形 dp。
- 考场 \(0\),死因:每一层需要清空数组。yyb 致命提问:你为什么不对拍呢?
T2 树网的核
直接枚举点,dfs 过程中判断路径长度是否合法,继而枚举不在路径上的点算贡献即可。
- 考场 \(70\),死因:数据范围这么小为什么一定要优化暴力。
T3 子串
原题,一眼 \(f_{i,j,k}\) 表示 A 串枚举到第 \(i\) 位,B 串枚举到第 \(j\) 位,已经使用过 \(k\) 段的方案,转移显然。
- 考场 \(50\),死因:vector 开大了。
T4 运输计划
一眼树上差分,二分最短时间即可。
- 考场 \(10\),死因:数组开小了,挂了 \(50\)。
反思
yyb 这几天还是非常用心的与我们分享了题目的解法,我也深感收获,不仅收获了题目的解法,也收获了各种策略与方法,同时这几次考试也暴露了我很多严重问题,需要反思并改正这些错误。
需要自查的点
-
题目
不会做先要手玩,考试先通读题目,合理分配时间。
先写暴力了吗,一定要写对拍,不行就自己手玩造几个数据。
数据点尽量分治,没把握的千万得加上暴力。
看清楚输出什么了吗?看清楚要求什么了吗?题目到底有什么性质?
看清数据范围了吗?需不需要开 long long 什么的?
题目部分分可以拿到吗?给的特殊性质手玩一下有什么很好求的方法呢?
-
时间复杂度
分析清楚了吗? 是否可以优化?
询问较少是否可以离线? 是否可以用bitset、数据结构优化一些东西? -
取模
不宜过多(TLE)与过少(WA),需要注意模数,从题面复制。
注意模数是否为质数? 哈希时多取几个模数? -
图论
是否有重边?有特殊性质的图(如树、基环树)?
\(\text{dijkstra}\):
priority_queue是否 pop 了? 标记了vis吗?\(\text{spfa}\): 看清楚题目有负权边了吗? \(O(nm)\) 是否可以过呢?
-
数学
lcm 不能边算边取模。期望指的是所有结果乘出现这种结果的概率(是否出现的结果有多种可能性?)
碰到很牛的式子拆一下,说不定有什么最优策略或前缀和、前缀积优化。
-
dp
转移需要的东西扔进状态。
是否可以滚掉?是否可以前缀和之类的?是否有最大值,可以用线段树维护?
收获的一些做题方法以及 trick
- 不要太快的否定自己的思路,仔细分析时间复杂度再下定结论。
- 整体数据范围较小,一类数据范围过大,可以思考是否可以矩阵优化。
- 带修改 dp 不一定是 ddp,说不定又跟矩阵有关系。
- 区间取模需要维护最大值,否则时间复杂度错误。
- 求某个东西计数结果的平方等价于将这个东西自己与自己匹配。
- 正难则反/时间倒流
薄弱的地方:
- 不想写对拍。
- 写正解非常自信,几乎不检查,过了大样例就万岁,没有大样例就跳了。
- 不会 dp,不会各种图论题目。
- 死钢题,有时间观念但总是想着等一会儿就做出来了。
- 多用纸笔画一画,看到式子多推一推。
- 暴力要打,要狠狠的打!相信自己的暴力。
需要改变的点:
- 不要每一点思路就去看题解,还是需要锻炼思维的过程。实在不行看看 tag,点明一下思路,实在没有一点就看看题解的主要思路,不要对着代码在那里假装搞懂了做题。
- 交洛谷题目时不要任性,测个样例就直接交,现在题目不想对拍、检查的习惯就是这么养成的。耐心思考下写对拍,不要一言不合就下数据。
- 学习自己不会、薄弱的专题,比如 dp、数据结构、图论等。
- 多自己思考,不要自己错了就去找别人帮忙,养成了不会自己调试的习惯。
- 养成良好的代码习惯。像 yyb 所说,如果不养成良好的代码习惯,以后写代码长的题目将会几乎无法调试。
yyb 为我们付出了很多,以后有什么无法解决的问题会麻烦他的,感谢他的善言警醒了我,让我得到了反思与成长。

浙公网安备 33010602011771号