• ZJOI2018 Day2 滚粗记 + 流水账


    一脸懵逼地就被直接拉过来浙江省选了,一年参加两次省选成就达成……

    讲课啥的都没听,过去休息了一天就进行比赛了。考试之前感冒没好透,精神不是 (100\%) 的状态,但是并无大碍(反正最后都很凉)。

    这次是 8:00 到 13:00 的标准 OI 比赛时间,五个小时三道题。

    题目连接应该在 loj 上可以找到:T1T2T3

    首先拿到第一题,树的计数,这种复杂计数的问题对于我而言向来都是打暴力,不知为何我想了一会才往下看题……

    看到第二题,是统计一个最短路算法的类似复杂度的东西(但不是复杂度,准确来说是每次更新节点的个数之和),看完题目就瞬间有了一些 idea,所以预感这题可能 AC。

    然后去看第三题,一个计算几何,而且不是无脑模拟或用数据结构优化、乱搞的那种,完全不会做。(考后才知道这个是一个反演,我从来没有接触过的东西。它的变换所有点就是关于某个点朝靠近或远离的方向移动,移动后和移动前和这个点的距离互为倒数;然后那个中心点等概率出现在一个矩形区域内部,问你变换一次后的凸包点数期望)然而发现有一个测试点 (n le 3),后面又保证了所有测试点有 (n ge 3),这答案不就是 (3) 吗,直接输出拿 (10) 分走人。

    回过去看 T2,顺着刚才闪现的灵感想了下去(在想之前我先打了一个暴力并过掉了小样例和大样例)……它求的是点权变化次数总和,那么我们可以换一种统计方式,变成统计每个点变化过多少次不就行了吗?想了想发现这样就变成水题了,因为我想的是找到每个点它最终是从左边哪个点更新过来的、从右边哪个点更新过来的,然后左右这两个点之间的点的个数就是答案……手算了一下样例发现过不了,所以感觉自己是漏掉了一些“细节”——原来我没有考虑距离问题,也就是说假设我研究的点是点 (u),它最终从 (v) 更新过来的,那么 (u)(v) 之间的边的数量需要向另一个方向倍长,然后得到的这个区间内的点数才是答案……然后自以为这个肯定是正确结论了,于是想了半天如何处理这个问题,由于我研究的点是一段一段的,不能暴力研究每个点(否则复杂度退化成每次询问都要 (O(n))),以为用主席树啥的暴力搞;后来不知什么时候突然发现这个结论的严重 bug,其实应该是左边、右边单调栈各一段,按照和点 (u) 的距离合并的单调栈大小(就是说这个区间内不一定所有点都会更新到 (u),只有往两边不断变小才会更新);那我想单调栈合并不可能快速进行啊,感觉非常不对劲,于是打算推翻之前的想法,换另一个思路。

    其实统计变化次数不一定要统计每个城市变化次数,可以统计每个给出的关键点的影响范围大小,这个影响范围大小的总和也是答案。然后一眼看出这个“影响范围”就是一个区间,所以我们需要二分来确定两个端点的位置。我想一个关键点是有可能“吃掉”另一个关键点的,(a) 吃掉 (b) 意味着最终最短路不会从 (b) 出发,那么这时 (a) 的影响范围完全包含 (b)。(以下只讲求右端点)所以我就先二分这个 (a) 会吃掉哪些关键点,然后影响范围一定在最远的被吃掉的关键点的右边,那么这个时候再二分一下不就行了吗?我于是立刻敲起了代码,调了一会过掉了小样例,接下来就去测大样例,发现似乎只有第一个询问对了;我重新想了一下这个思路,感觉没啥漏洞,没办法只好和暴力用小一点的数据对拍。

    没想到随便生成一组数据就拍出错了,于是我就看这个数据,发现了我刚才思路的漏洞:限制我影响区间不能往后扩的的不只有第一个没被吃掉的关键点,后面的关键点可能会有更强的限制……于是我就想,最强的限制不就是 (v_i + S_{i-1})(v_i) 就是关键点的初始值,(S_i)(w_i) 的前缀和)最小的关键点吗?直接用它限制就好了。改了一下代码,再拍,还有错,但错误明显变少了。接着找问题,这个想法还是有漏洞:注意到假设关键点 (b) 限制了关键点 (a),那么我是要二分到那个从 (a) 更新比从 (b) 更新更小的最靠右的点 (x),这个 (x) 就是 (b)(a) 的限制,但如果这个 (x)(a)(b) 的中点(这个中点是假设边权都为 (1) 的中点,就是只数边的条数)左边,这个 (b)(a) 就没有任何限制了(或者应该说限制不是 (x) 而是 (a)(b) 的中点),所以我们要排除掉这些没有限制的点。于是我想我需要处理每个点右边离它最近的且权值 (v_j - S_{j-1}) 比他小的点,这样维护一棵树,那么我们就可以在某个点到根的链上进行二分了(为什么可以二分呢?那是因为随着往根上走,中点会越来越靠右,限制点会越来越靠左,所以是单调的,我们可以二分到“限制有效”的那个点),于是搞个树上倍增就可以 (O(log^2 n)) 解决了。

    想到这里,发现已经 9:15 了,T1 暴力还没打呢,这个正解代码也不知道写不写得完了——又是一个艰难的选择。这里我选择了求稳,我去打了 T1 的暴力(原因是 T1 暴力看上去非常好写;而且当时我想 T2 时间太久我不确定我是否还足够理智,不确定最终的那个想法是否还有漏洞,如果有,那我正常比赛就完全挂掉了,连暴力分都没拿满,不值得用整场比赛赌一个不知道是否正确的正解),打完暴力只剩 (10) 分钟了,我把 T2 那个写了一半的“正解”和暴力拼了起来,过掉了小样例、大样例,然后查一下三道题的目录、文件读写等等就结束了。

    考后发现 T2 正解非常简单,根本不需要先二分“吃掉”哪些关键点,直接二分求区间端点就好了,程序实现、思路上都会简洁许多。最后在 loj 上过掉了。考场上最后想出的做法没有实际验证,但是从思路上看没有漏洞了。


    总结一下,这次比赛思路上走的弯路非常多,T2 我想错了至少 (4) 次,每次都还觉得挺对,没有及时意识到错误直接开始考虑程序怎么写,导致过量时间的浪费,造成一个小小的遗憾(如果 A 掉 T2 应该就全场 rank 1 了)……并且想错是一件很可怕的事情,最后我的那个正解想先二分被“吃掉”的关键点受的就是之前“考虑求每个点被改多少次”的思路的影响,拐了很多弯,没有找到最直接、最有效、最简洁、最优美的做法;其实我觉得即便考场上我调出来了 T2,用的如果是那个复杂的做法的话也是值得反思的。这次我想到了正解,说明水平也没那么差劲,但这次想到的正解也反应出来我的思维水平还没有达到一定的高度,我在想错之后没能够完全跳出错误的圈子,而是多少仍然受着影响……想错可能无法避免,所以我们在努力尝试想对的同时似乎也应该准备一下想错后的“应急方案”。

    这场比赛也有不错的几点:

    • 首先我找准了场上最能 AC 的一道题,并且不管怎么样还是想出来了。
    • 我能及时放弃,做出正确的选择(指的是放弃 T2 写不完的正解,选择打 T1 暴力),我认为考场上求稳比赌命要好很多。
    • 在最后的时刻打 T1 暴力我能做到很快打对,说明比之前冷静,考试心态调整得不错。

    最后祝愿自己在之后的比赛中稳定发挥,拿到有能力拿的分,写完能想到的 idea。

  • 相关阅读:
    JS---DOM---点击操作---part1---20个案例
    JS---体验DOM操作
    JS---课程介绍 + JavaScript分三个部分
    JS---DOM/BOM---学习road map---7 parts
    JS基础语法---基本包装类型
    JS基础语法---Array对象的方法
    JS基础语法---String(字符串的案例)
    Python老司机告诉你,学习Python应该看哪些书比较好,看这基本就够了
    Python实现远程开关机【高薪必备技术】
    大四学长教你利用Python写一款超级玛丽,零基础也能学会,超级装逼
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/8976621.html
Copyright © 2020-2023  润新知