Um_nik 的人生智慧
Andycode3759 · · 个人记录
翻译自这篇博文。
不要关心 Rating / 等级分
一场比赛中的名次对于选手来说没有任何意义(有评奖的情况下除外)。即使我在一场比赛里拿了榜一,但是有一道本来应该能做的题没做出来,我也会很伤心。再比如,如果我把所有会做的问题都解决了,就算掉了大分我也很高兴。Rating 只是一个数字,一个不断变化、高度依赖于他人表现而不是你自己的水平的数字。解决问题才能够体现出你的真实水平。你对于自己水平的评价应该基于发自内心的期望,而不是随便拿个公式一算。对自我的理解应该在自己的掌握之下,不要被一些数字所组成的虚像所困扰,更不要仅仅用一个数字来概括你的全部努力。
不要开小号
Rating 只是一个数字。名字掉色了也不要紧。只要保持进步,彩名终究有回来的一天。
你也不应该开小号来在 OJ 讨论区上灌水。如果你觉得自己发布的东西不好,不应该跟你的主帐号关联在一起,那你就不应该发这些东西。要么讲个让自己很满意的笑话(然后发在主帐号上),要么什么都别说。
多打模拟赛
你可能觉得自己太菜了,在开始限时竞赛之前还应该多练些题。诚然,刷题很重要,但是如果没有模拟赛的经验,你在真正处于压力中时就不能保持镇定。学着做某件事的最好方法就是尝试去做这件事。
卸载 Rating 预测程序
这种东西的意义何在?它能帮你在赛场上做出选择吗?开题时先做哪道还是先 Hack 谁?毫无意义。这种东西可能会给你提供动力,但是它也可以通过提供虚假的安全感来毁掉你的赛场发挥能力。
再说了,Rating 只是一个数字。比赛的目标有且仅有一个:多拿分/多 A 题。Hack 也是在做题之外才考虑的。专注于解决问题,仅此而已。一场比赛无非就是可以让你集中注意力思考一些新问题的时间段而已。
Rating 变化无常,涨 Rating 的成就感跟买彩票中奖并无二异。你应该为解决了问题而感到自豪,而不是名次或 Rating 的变化。
刷 AtCoder
无须解释,刷就完了。
不要把某些算法 / 思路往题目上硬套
引用:On "is this greedy or DP", forcing and rubber bands
你可以(而且应该)思考“这道题能贪心吗?这道题可以 DP 吗?”之类的问题,但是不应该认为这道题的解法仅限于某个特定的套路,从而把这个套路往这道题上硬套。
一个特例是根据数据范围和潜在条件来猜测一道题的正解做法和复杂度。的确,知道正解的复杂度对于解题来说是有好处的,但是这一信息无法 100% 由数据范围得出,而且这也不会提示你该用什么解法。
还有,不要先选定模板再做题。模板只是帮助你写出高效程序的工具。举个栗子,某人要你拼装某件家具,你肯定不会连说明书都不看就说“拿个活动扳手就够了”。当然这个栗子可能不太恰当,首先你没有说明书,你应该写出自己的说明书,这一步就叫解决问题;而且你的大脑就是你的工具箱,把你有的所有工具都试一遍不会损失任何东西。
不要在连
学会问自己问题
读题时:
- 为什么有这个限制条件?如果去掉的话解法会变成什么样?
- 有没有什么反常之处?
- 问题要求我做什么?
- 能不能把这个问题转化为某个套路?或者是某个套路的变形?或者是某个难题(例如 NP-Complete 类等)的特殊情况?
解题时:
- 如果把问题简化后该怎么解决?尝试缩小题目限制?尝试将模型进行变形:图 → 连通图 → 仙人掌 → 无环图 → 树 → 链或菊花;矩阵 → 链?变形的过程中能不能给正解带来某些启发?
- 如何解决单次询问?
- 手玩样例该怎么玩?去掉时间/内存限制可以怎么做?
写代码前:
- 复杂度多少?
- 有正确理解题意吗?
- 要实现什么功能?
- 哪些地方细节多容易出错?要遵循什么原则才能写对?
- 哪些地方码量最大?能不能简化?
- 哪些地方跑得最慢?需不需要注意常数?有没有稍慢但更简单的实现方法?
没有 AC 时:
- 之前需要注意的细节地方有全部写对吗?
- 解法本身是正确的吗?
- 有正确理解题意吗?
成功找到 Hack 数据时:
- 程序行为是否符合预期?
- 是代码写得有问题还是解法有问题?
对拍没能找出漏洞时:
- 暴力做法是绝对保证正确的吗?有没有套用正解里的某些假设或结论?
- 有没有生成所有可能的测试数据?题目是否有多组输入?如果有,数据生成器和答案程序有没有正确处理?
A 完一道题后:
- 哪里还能做得更好?
- 哪些地方花的时间比预期要久?
- 有没有技巧能简化实现?
不要按知识点刷题
不要看题目的算法标签,它们就像追番前的剧透一样会毁掉做题的体验和效果。
“你说的对,但是‘学着做某件事的最好方法就是尝试去做这件事’呀!我想练练 DP,那么我就得刷点 DP 题。”
道理很对,但是结论错了。你需要提高的能力不仅仅是能解决 DP 题,更重要的是能看出一道题应该用 DP。如果按知识点刷题,你就跳过了识别题目知识点的这一步,而是直接开题然后套 DP。你并不了解为什么这些题可以用 DP,也没有体验到从读题到 Get 到 DP 想法的整个过程。
长期如此导致的后果就是,如果在做题时不给你任何标签(比如在一场比赛中),你就会不知从何处下手,哪怕后面的每一步你都完全掌握。
补题
假设你的目标是能在 Codeforces Div2 成功签到前三题。达成这一目标的最好方法就是确保每一场 Div2 的前三题都能做对,但不一定要在赛时。可以赛后补题!试着独立解决问题,实在做不出看题解也行。如果题解里有某些无法理解的地方,试着借助他人的代码来理解。
补题不能代替日常练习,而是在此基础上的额外补充。各大 OJ 的题库是刷不完的,并且有相当数量的题目很有年代感,你可以以此作为心理安慰来跳过平时作业“随便一半”的题目,但实际上这些题目并不随便,而是你潜意识中不喜欢的题目。通过赛后补题,你可以确保自己的知识点掌握全面。
学着做某件事的最好方法就是尝试去做这件事。
出题时不要给题目强加解法
我没资格教别人怎么成为一位合格的出题人,但有一个事实:为了某个解法而出一道题并不意味着这个解法就是本题的最优解。你可能觉得自己出了一道非常 NB 的数据结构题,结果却发现贪心做法更快还更简单。如果你想通过添加限制条件来卡掉简单的解法,这只会让题面变得更加丑陋,说不定还会通过限制条件直接泄漏正解。
然而,这并不妨碍你从身边的一切地方得到题目的 idea 和灵感,而且从解法开始入手对于刚开始出题的萌新来说是个好的选择。学些新知识点也是出题的妙招之一,即使到最后没想出相关的题目也不要紧,关键是了解如何构建相关情景下的数学模型。如果你想出道题,你应该理性看待自己的解法,把它看作“解法之一”,而不是“正确解法”。出题人自己的解法并不一定是解决这道题最快或最好的方法。