3.16 考试总结

3.16 考试总结

这次考试考的不好,原因分以下几点:

  1. 算法掌握不够熟练灵活,实现能力不够强;
  2. 数学直觉不够强烈,思维拘泥于死板的传统信竞题中;
  3. 对复杂度和常数的分析不够精确。

第一个问题,体现在树剖算法以及其灵活运用上,

具体来说,树剖的本质,是用已经预处理好的重链,来将任意一条路径切割成较少的部分,

本场考试中的第一题,我们正是用树剖对路径的切割,来代替倍增的跳链,从而尽量的减少了重复计算。

同时,在实现能力上,我并没有思考到高效的实现方式来实现我的思路,

具体来说,在向下跳链时,可以先处理出路径的所有切割点,就能高效准确的向下跳链。

这个问题的解决方法只能是多练,多思考算法的本质以及其核心,

同时在写代码时一定先自己写,写完之后可以看别人的优秀实现。

第二个问题,体现在对几何问题与代数问题的灵活转化上,

具体来说,从若干二维向量中找到一个,并最大化其与某个给定向量的点积,

这种问题可以抽象成,从平面上的若干个点中选取一个,并最大化斜率给定且过该点的一次函数的截距,

这也是斜率优化算法的核心,考虑求出所有点形成的上凸壳,即能快速地在凸壳上维护最大答案。

这个问题的解决方法,是多从不同角度思考问题,不要拘泥于固定的思考方法。

第三个问题,具体在对该次考试中第一题的运行效率分析上,

当时认为双 \(\log\) 的二分倍增哈希的复杂度正确,却忽略了算法常数的问题,

如算法本身的读入输出量大,求倍增时的寻址不连续,以及哈希取模的速度较慢。

对算法运行的效率的错误估计,导致了我没有继续想复杂度更优,或者常数更小的做法,

这也成为了阻碍我得到更多分的原因之一。

这个问题的解决办法,是可以先得到一种恰好要运行一秒的程序,

再在考试电脑上运行同样的程序,从而得到较为精确的考试电脑的秒运行次数。

接下来写下对每道题具体做法的总结。

A. string

这道题中,一个好想的思路,是直接二分加哈希,在二分时需要支持判断两路径串是否相等,

我们可以用树上 \(k\) 级祖先与树上最近公共祖先,配合字符串哈希来完成。

暴力的实现是 \(O(q\log^2n)\) 的,但若用 \(O(1)\) \(k\) 级祖先和 \(O(1)\) LCA 就可以做到 \(O(q\log n)\)

但这样的复杂度很容易卡满,且常数也较大,是不能通过的。

而实际上我们会发现,在二分以及求路径哈希值时,二分与倍增长剖并不是很契合,

即有很多段路径的哈希值被我们算了很多次。

那一个自然的思路是尝试直接倍增跳链并判断,但我们会发现,倍增似乎无法进行往下跳的过程,

但实际上,我们可以在向上跳的时候预处理每一个跳点,就能实现向下跳的过程。

但因为倍增的复杂度很容易卡的比较满,且在求链哈希值时需要做树上差分,

而由于树剖的每一条重链所有点的 dfs 序连续,这使得我们可以直接转化为求序列哈希值,

故我们也考虑使用树剖来跳链,就能通过本题了。

B. joker

因为看上去除法不如乘法好处理,故我们直接将分母乘上去,

就变成了一个一次函数线性规划问题,若没有修改就可以直接维护凸包,做到线性复杂度。

而考虑如果有修改,则我们就可以尝试维护凸包,使其支持快速修改和查询。

看上去并没有什么好的想法,那就考虑分块,我们考虑分块后对每个块维护凸包。

发现这样的话,我们修改一个点值,等价于将后缀所有点的横纵坐标分别加上一个偏移量,

而若同一个块中的所有数都被加上同一个偏移量,则该块的凸包形状是不会改变的,

故在修改时,我们暴力重构修改点所在块,并对后面所有块打上偏移量标记即可。

而在查询时,我们需要遍历每个块并二分找到答案,那我们设块大小为 \(B\)

则时间复杂度就是 \(O(N(B+\frac{N\log B}{B}))\),取 \(B=\sqrt{N\log N}\),则总复杂度就是 \(O(N\sqrt{N\log N})\)

注意到取 \(B=\sqrt{N\log N}\) 时会有 \(NB>\frac{N^2\log B}{B}\),故我们稍微将 \(B\) 调小会快一些。

这道题中汲取的经验有两点,一是,在做数据结构题且没思路时可以尝试使用分块,

原因是在暴力的修改和查询的复杂度不平衡时可以用分块来平衡复杂度,

以及在某些特殊的信息不具有结合律而无法使用线段树维护时可以用分块解决。

C. game

首先可以将异或理解成加一后模二,发现模二不好处理,故我们考虑去掉模二后的问题,发现其与原问题等价。

然后似乎卡住了,我们考虑 SG 函数,因为每个有值的点独立,故只需考虑一棵只有根有值的树的 SG 值。

发现一棵只有根有值的树的 SG 值为 \(2\) 的树高次方,证明也是简单的,只需考虑那条连接根和最深叶子的链,

故此时我们可以构造出所有 SG 值小于 \(2\) 的树高次方的后继,且永无法构造出 SG 值为 \(2\) 的树高次方的后继。

此时这题就做完了,只需用桶存 SG 值即可。

这个题汲取的经验是,思考问题要从多个角度,例如在做博弈论问题时,

不仅要从性质角度思考,也要从 SG 函数角度思考,在没有思路时也应将表打出来。

posted @ 2022-05-29 19:22  GaryH  阅读(39)  评论(0编辑  收藏  举报