A Way to Practice Competitive Programming(一种程序设计竞赛的训练方 译日:永田正彦)
Rating从1000到2400+
2019年5月7日
Masataka Yoneda/E869120
- 1. 自我介绍
- 2-1. Codeforces [http://codeforces.com/]
- 2-2. AtCoder [https://atcoder.jp/]
- 2-3. TopCoder
- 2-4. 这部分的总结
- 3. 训练方法介绍
- 3-1. 训练技巧 rating 1000~1400
- 3-2. 训练技巧 rating 1400~1900
- 3-3. 训练技巧 rating 1900~2200
- 3-4. 训练技巧 rating 2200~2400
- 4.训练心理
- 5. 虚拟赛推荐
- 6. 未来愿景
- 7. 总结
1. 自我介绍
亲爱的CF社区:
2019年4月20日,在14场比赛后,我终于达到了grandmaster,rating 2426。在最后一场比赛之前,我很遗憾rating是2399,距离成为粉名只差1分。所以上一场比赛(Forethought Future Cup Elimination Round) 是我印象最深的比赛之一。感谢CF举办这些比赛,感谢友善、出色且给人留下深刻印象的CF社区接受我的博客。
如今,我也想给CF社区做一点贡献,因为我之前在CF社区收获了很多,心里十分感激。我思考了很长时间“如何给CF做贡献”,或者说以一种合适的方式给CF做贡献。我想到了:介绍一种从灰名到粉名的练习方法。
现在,我要解释如何成为一个红名大佬。
2017年7月,我写了一篇博客解释如何到紫名(http://codeforces.com/blog/entry/53341) 。凭借这篇博客,我得到了181个赞,但那里面有很多语法错误,而且还有几个地方没有解释清楚。我很抱歉自己不擅长英语,也不是一个很好的作者。这次的博客可能还是有一些错误,但我努力使它更易读易懂。感谢你的合作、陪伴。
这次,我要分几个步骤进行讲解,因为rating范围有好几个,大部分人并不能一步就从灰名到达粉名,我也不能。所以这次我要分成下面的四个步骤:
-
- Rating 1000→14001000→1400,从灰名到青名
- Rating 1400→19001400→1900,从青名到前10%的选手
- Rating 1900→22001900→2200,从前10%选手到表现优异的Div1选手
- Rating 2200→24002200→2400,从表现优异的Div1选手到粉名
另外,在解释如何练习之前,因为CF用户很多,其中一些并不知道其他的OJ,所以我想介绍一下其他的在线比赛网站(AtCoder、TopCoder等)。
还有,很高兴你们阅读我的博客。非常感谢CF。
永田正彦
## 2. 常识介绍——一些打比赛的网站世界上有很多OJ。为了成为粉名,我切了很多OJ上的很多题目。这次,为了 explain the post sections,我想先介绍一些比赛。
2-1. Codeforces [http://codeforces.com/]
Codeforces是世界上最有名的OJ之一,目前有五千多题。
利用CF的最好方式之一是“题目Rating”。例如,1146H Satanic Panic 的Rating是2800,这意味着,如果你的rating大于等于2800,那么你应该在比赛中切掉这个题。
另外,CF分成三个部分(Div1、Div2、Div3)。
再往后,我会使用下面两种简称:
- Div1A, Div2E等等:代表Div1的A题、Div2的E题。通常,第一题是最简单的,最后一题是最难的。
- 难度R2800什么的:“难度R2800”代表这题难度被标成2800。例如,1146G Zoning Restriction 难度R2600,1146A Love "A"难度R600。
2-2. AtCoder [https://atcoder.jp/]
AtCoder是一个“拥有很多好题”的比赛网站。这只是个人意见,但如果你想变强,就要刷AtCoder。
AtCoder有三种类型的比赛:
- AtCoder Beginner Contest (ABC) : 有4道题。
- ABC难度一般为R500-R700-R900-R1400。
- AtCoder Regular Contest (ARC) : 有4道题。通常ARC的前两题和ABC的后两题是相同的。
- ARC难度一般为R900-R1400-R2100-R2600,因比赛而异。
- AtCoder Grand Contest (AGC) : 有6道题。
- AGC难度一般是 R1200- R1900- R2200- R2500-R3000-R3300
还有个很方便的网站——AtCoder problems(https://kenkoooo.com/atcoder#/table//)。
在这个网站,你可以看到自己AtCoder的切题列表,知道自己哪些题还没做,哪些题做了。AC的被标成绿色,尝试过但没AC的被标成黄色。
2-3. TopCoder
TopCoder也是一个著名的比赛网站。Single Round Match (SRM) 有两个部分:
- Division 2:有三道题,R600-R1300-R2100,被称为Div2简单、Div2中等、Div2困难。
- Division 1:有三道题,R1800-R2400-R3000,被称为Div1简单、Div1中等、Div1困难。
我为了到粉名,也用TopCoder训练。尽管主要是数学题,但都是好题(我尤其喜欢SRM600-699)。
2-4. 这部分的总结
我主要用3个OJ训练:Codeforces、AtCoder、TopCoder。如果你了解了这3个OJ,就可以去阅读下一个部分了。在这些比赛网站训练是很重要也很有效的,而且我觉得这是最快的进步方式。
在第3部分,我会写很多要点,但都只是我的个人观点,不信任我也是可以的。很多人遵循我的方法,取得了很大的进步,但也有很多人没遵循我的方法依然取得很大进步。用我的方法训练是挺好,但不一定对所有人都有效。
3. 训练方法介绍
可能有很多人读过我上一篇教程博客,但现在和两年前不一样了。这两年我有很多遗憾。很多事情我没做,但我在想,如果我做了,是不是可以进步更快?因此,这篇博客和我之前那篇有很多不同之处。
此外,在rating到达2200前和到达2200后,我的训练方式完全不同。
还有一件事,这篇博客只是我的个人观点,训练方法因人而异,所以我认为你不一定按照我的方法训练。但我觉得我的方法对一些人来说是最有效的。
如果你理解了这一点,就可以继续往下读了。进入正题……3、2、1,走起!
3-1. 训练技巧 rating 1000~1400
CF上有很多灰名、绿名,他们很想成为青名、蓝名,但依然在苦苦挣扎中。
尽管如此,到达青名(1400)只需要做到三点。
- 能够快速写出模拟题(5到10分钟内)
- 能够快速写出暴力(5到10分钟内)
- 能够在脑子里或草稿纸上把问题分情况讨论(例如,N=2、N=3、N>=4)
举个例子,在Codeforces Round #556中,如果你可以做到以上三点,就可以很惊喜地在Div2中达到200名,这是一个很夸张的例子。但在Codeforces Round #554 (Div. 2)中,你只能达到3400名,rating1250及以下的参赛者可以上分。
平均来说,如果你可以做到以上三点,rating就可以达到1400。
[[如何训练]]
首先,我建议你打ABC。
尽管CF上有很多好题,但如果你想更容易地练习编程,最好去刷AtCoder。
特别地,我推荐做ABC中的B题和C题。做B题可以学到如何更快地写模拟和暴力,做C题可以学到如何想题、如何用草稿纸更快地想出解决方案。
从ABC 042开始,出题人加入了英文题面。目前最新的一场是ABC 125,所以共有84场可做的ABC。如果你切了所有的B题和C题,就会学到很多,变得更强。
可以借助AtCoder problems的帮助刷AtCoder,你能从这个网站知道自己做了哪些题。
当你刷AtCoder时,有几点很重要:
- 当你想不出解决方案时,应该在思考B题15分钟、思考C题30分钟后再看题解。可悲的是,最近几场ABC没有英文题解,但你可以读标程(题解中很可能包含标程的链接)。
- 即使你AC了某道题,在习惯快速写代码前,还是可以通过阅读大佬的源代码学到一些东西。所以我建议看一些简单的源代码。
- 特别是当你做C题时,我推荐你用草稿纸辅助思考。不用纸的话,用白板打草稿也可以。
我是高中一个计算机社团的社长,有很多社员用这样的方法获得了进步。
3-2. 训练技巧 rating 1400~1900
CF上人数最多的rating区间是[1400, 1500]。他们都很想上分,但从1500开始上分比较困难,很多人放弃了。但也有很多人坚持训练,成功上分。
要达到1900,需要下面的技巧:
-
掌握并能够使用以下主要算法:
- 暴力
- 动态规划
- 深度优先搜索
- 广度优先搜索
- 迪杰斯特拉
- 树状数组
- 排列数、组合数
- 乘法逆元
- 位掩码
- 二分查找
注意:我认为在rating 1800前,线段树不是必须的。我上紫以后才学的线段树。
-
提高手速(例如,R1100的题目5分钟写好,R1400的题目10分钟写好)。手速在CF很重要,因为一般来说,如果题目难度范围很大,手速会在很大程度上影响rating。
[[如何训练]]
如果你不擅长快速写代码、快速调试,就应该刷AtCoder。事实上,从统计学上讲,很多日本选手手速很快,但不擅长解决难题,我觉得是AtCoder的锅。
我推荐做ABC的C题和D题。平均来说,如果能在10分钟内解决C题,在20分钟内解决D题,你就是手速场中的Div1 😃
如果你不擅长解难度高于R1400的题,就应该学一些上面提到的算法,做做CF上的板题。举个例子,如果你觉得自己不擅长DP,就刷CF上R1200到R1400的DP标签的题。让人惊讶的是,只有约50道难度小于等于R1400的DP标签的题。
有趣的是,板题都集中在只有Div2的那些比赛中。如果你不擅长只有Div2的比赛,那么很可能是你不擅长使用典型算法,尤其是上面提到的10种算法。
如果你能做板题,但不擅长做难度高于R1500的题,就要开始在TopCoder刷题。这类练习对擅长只有Div2的比赛但不擅长Div1+Div2一体的、分开的比赛的人十分有效。
有时候,尤其是在Div1+Div2的比赛中,一些题目需要数学概念或者思考。因为TopCoder上有很多题用到这些(另外还有简便的实现!),所以你应该刷TopCoder。
我推荐刷最近100场SRM的Div1简单。但有些题真的太难了(甚至粉名都切不掉),所以刷之前,你应该看一下题目的通过率。你可以利用https://competitiveprogramming.info/来获取一些信息。
不幸的是,我不知道有没有像AtCoder Problems那样,能够看自己在TopCoder SRM中做过哪些题的网站。所以,如果你想记录自己刷过那些题,应该做一个电子表格或者表格。这是我哥哥两年前使用的电子表格(Sorry for Japanese, but there are no Japanese in Div1Medium page, so you can refer to it没看懂这句话
)https://drive.google.com/file/d/1mSy9PM4Km8EVv8Lp4nhitorOe2HbAS1e/view?usp=sharing
当我还是个蓝名时,数学思维也很糟糕。在切了50题Div1简单以后,我在TopCoder成了蓝名,在CF成了紫名。
如果你擅长切题,但在比赛中发挥不好,就应该多打虚拟赛。你知道CF的虚拟赛系统吗?你可以虚拟参赛!
3-3. 训练技巧 rating 1900~2200
如果你想达到2200,首先,你应该是Div1,并且参加Div1的比赛。这意味着你应该刷很多难题(R1900或更高)。
即使你手速快或者十分擅长切板题,打Div1比赛也是很难的。可悲的是,有很多选手在蓝名和紫名之间摇摆
要达到2200,需要以下技巧:
- 知道并且会用上面提到的10种算法,还要加个线段树(包括懒标记)
- 非常快的手速:R1100 5分钟,R1500 10分钟,R1800 15分钟,R2000 40分钟。
- 相当好的数学思维和思考问题的能力。
- 强大的思维,可以支持超过1小时的思考,即使在Div1比赛中途落后了也不放弃。
[[如何训练]]
这只是我的训练方式:在rating2000时打了很多虚拟比赛。在这里,虚拟比赛并不意味着“虚拟参与”,而是选择4到5道难度在自己rating附近的题目(举个例子,目前rating是2000,那么选择CF中R2000的题目),并且在2小时内切掉。
你可以利用https://vjudge.net/。在这个网站,你可以从很多OJ上(AtCoder、CF、Hackerrank、Codechef、POJ……)拉题组一场虚拟赛。
如果你在虚拟赛中不能切掉这些题,而且没有想出解决方案,就应该去谷歌查题解(举个例子,如果你想找Codeforces Round #556 (Div. 1)的题解,就去谷歌搜“Codeforces Round #556 editorial”)。
在CF上分还有一件重要的事。为了更快的手速,你应该准备一些板子。例如,我认为线段树板子、懒标记线段树板子、CRT的板子、FFT的板子、计算几何板子等等都是很有效的。
3-4. 训练技巧 rating 2200~2400
这是本博客关于训练技巧的最后一部分。事实上,我卡在橙名很久了,就连在虚拟赛中,我的平均表现也是橙名。这是因为我之前的训练方法在橙名遇到了障碍。
Rating 2200到2400事实上非常难——如果你平均表现2200,如果你练习赛打得更多,上粉(到2400)看上去也没那么难。但是平均表现2400比你想象的要难得多。如果你的rating正好是2400,那么在Div1的比赛上,你一般要打进前20%(例如,如果有525人参加,那么你应该最差在105名)才能上分。
要达到2400,需要以下技巧:
- Rating达到2200
- 在Div1比赛中切掉AC少于100人的难题
如果你想切难题和用ad-hoc临时方法的题,根据TozanSoutherPacks在我上一篇博客下的评论(http://codeforces.com/blog/entry/53341?#comment-373965),“要达到2600分乃至更高,你应该切Boss题,所有这些都是临时问题或者步骤很多的问题。”我觉得那是对的,但是对我来说,我觉得即使你只想达到2400分,切步骤很多的临时问题也是有必要的。
[[如何训练]]
达到2400分最安全的方法是“切4000道题”。我就在TopCoder、AtCoder、CF和一些日本OJ上切了超过4000题。
事实上,有一个传说(或者说是事实)是,最NB的选手tourist在他这辈子切了一万多题。
但是可能很多人觉得自己没时间。所以我会给你一些更高效的途径。
首先,AtCoder上有很多教育题。我推荐你做ARC尤其是ARC058到ARC090的E题和F题(尤其是AtCoder中700到900点的题目)。尽管以前的ARC在“思维”和“模板”之间是平衡的,但可悲的是,我认为AGC和最近的ARC实际上太偏向思维了,所以如果你的目标是在CF上分,我不推荐它们(尽管如果你想达到2600乃至更高,还是要刷AGC)。
对我来说,实际上,刷了ARC以后,我在CF虚拟赛的平均表现从2100提高到了2300(I could not reach 2400 because start was early)。
如果你切不动题,我推荐你放弃思考并且看题解的时间如下:
AtCoder点值 | CF难度 | 思考时间 |
---|---|---|
600 | R2000 | 40分钟 |
700 | R2200 | 50分钟 |
800 | R2400 | 60分钟 |
900 | R2600 | 70分钟 |
1000 | R2800 | 80分钟 |
如果你切了AtCoder上的教育题,你编程比赛的技能将会有所提高。但还有另一个问题,没有付诸实践,你没办法上分。
所以,你应该至少在CF上打50场虚拟赛(尤其是Div1)。在虚拟赛中,你可以学到,紫名、橙名应该如何打比赛(比如比赛策略),以及如何在CF比赛中利用在AtCoder学到的技巧。我强烈推荐在虚拟赛后看看所有题的题解,除了太难的题(比如在比赛中AC人数少于30的题)。我还建议,在打完比赛看完题解后在笔记本上写一些对于比赛策略、教训和可以改进的地方的反思。
此外,我建议你每周一次,花点时间思考一些难题(比如CF上R2800的题)。如果你想了很久也想不出来,我建议你去读题解,因为那样你可以学到很多。解决难题可能会给你一场上分100+的机会,也会给你更快解决简单题的机会。
最后,我猜这个方法对于超过30%的人奏效,因为我用这个方法在CF上粉,我的孪生兄弟square1001用这个方法在TopCoder上红。希望我的方法可以产生新的粉名:)
4.训练心理
心理问题是选手中最常见的问题之一。即使对我,直到最近两个月前,出于对一场掉分100+的恐惧,我超过9个月没打过CF上rated的比赛。另外,还有几场比赛我甚至都做不到看下一个题,因为我做不出来更简单的题,心态崩了。
我最近发现一种锻炼心态的办法。
- 制定一个比赛前的常规程序。这能让我们在比赛期间集中注意力。
- 事实上,就我而言,我的常规程序是在比赛快开始时看着倒计时减少到0。黑红大佬yutaka1999实际上在IOI开始前就在修禅。
- 如果你比赛中没发挥好(比如20分钟内切不掉B题),不去看榜也是个好主意。
- 还有一件重要的事:“比赛过程中不要管rating”。
- 我觉得,即使这场要掉分,下一场上分的可能性也提高了。这就是为什么我在比赛过程中不管rating。
- 不要过于在意之前犯过的错误。错误也是一次好的学习机会,每个人都会犯错。即使是tourist也曾经在AtCoder World Tour Finals上翻车。
- 我觉得吧,“rating”和“你犯过多少错、做过多少反思”之间存在关联。
以上这些方法不仅在正式比赛中适用,还在虚拟赛中适用。注意:比赛中不要有太大的压力,开心就好!
5. 虚拟赛推荐
在写关于虚拟赛的建议之前,我认为虚拟赛有以下两种类型:
- 虚拟参与:选择一场比赛,就像真实参赛那样做题。和CF的虚拟赛系统一样。
- 虚拟比赛:使用VJ或者其他的评测系统。从CF上挑几题难度在自己rating附近的题,并在2到3小时内解决它们。
首先,以上这两种方式我都推荐。
对于虚拟参与,我觉得你可以学到比赛策略、心态和其他一些比赛技巧。对于虚拟比赛,我觉得你可以集中精力卡一道题,因此解题、复习效率会得到提高。
这就是为什么当我在刷CF上的难题时,总是用VJ进行虚拟比赛。
如果你想在AtCoder打虚拟赛,用https://not-522.appspot.com/(遗憾的是这个网站是日文的,如果你不是日本人,只好委屈你用一下谷歌翻译了。。。)。
6. 未来愿景
幸运的是,在2019年4月29日,我CF的rating达到了2585,非常接近红名了。我很高兴,也真的很感激CF管理员和CF社区。
我实际上已经定下了未来的目标:黑红!
实际上,我最近在CF打了很多比赛或者虚拟赛。我在CF上最近10场比赛的表现是: 2865, 2661, 3029, 2890, 2858, 2875, 2318, 2717, 2506, 2891(平均2761.0)。
所以,我大概还差250分到达黑红。我为了实现梦想正在做的努力如下:
[[如何训练]]
- 几乎每天都打2到3小时虚拟赛。赛后看题解、看黑红大佬的代码,写一个小时反思。
- 有时候(大约一周一次)从CF上选大概5题左右(难度从R2200到R2800),在2到4小时内解决。
- 即使打比赛三年了,我还是觉得有很多黑科技(实际上和算法板子不同)是我不知道的。所以比赛中如果有超过20人做出来的题目我没做出来,我就会去看题解。
- 我觉得,如果我能在比赛中把几乎所有20个AC以上的题目做出来,早就是黑红了。
7. 总结
这就是我要给CF社区说的所有训练方法。真心感谢你的阅读。
我使用CF很久了,也在社区中得到了成长。所以,我想我应该给CF社区做点什么贡献。做贡献有很多方式,我选择讲述在CF上分的实用技巧。我认为这是给CF做有实际意义贡献的最好方式之一。
最后,我建议一步步用一定的训练方法提高你打比赛的能力。但是训练方法因人而异,我不觉得我的方法总是最高效的,同样,我也不认为你必须按照的我方法训练。
但我觉得,这对某些人来说是最高效的方法。希望这篇博客有用,即使只有一小点儿。
因为我只是日本的一个高二学生,文中可能有很多语法错误,我英语也确实不好。我必须表示歉意,但相反,我必须感谢读者。谢谢你的阅读。
最后,祝你好运,祝你在CF上分,祝你在程序设计竞赛玩得开心。这就是我这篇博客的总结。再次感谢。
永田正彦