【色変記事】数学超苦手なエンジニアがAtCoderで茶色コーダー(脱初心者)になるまで

【色変記事】数学超苦手なエンジニアがAtCoderで茶色コーダー(脱初心者)になるまで

Clock Icon2022.09.25

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは、AWS事業本部コンサルティング部に所属している今泉(@bun76235104)です。

ゴリゴリの文系だけどアルゴリズムや数学的考察力を身に付けたいマンです。

私は以前よりAtCoderという競技プログラミングのサービスでコンテストに出て学習をしています。(前回のコンテストの出場の際に書いた記事はこちらです)

この度トヨタ自動車プログラミングコンテスト2022(AtCoder Beginner Contest 270)でレートを400以上に上げ、茶色コーダーというものになることができました!

atcoder_changed_color_brown

茶色?レート?と思われる方も多いと思いますので、のちほど意味を記載させていただきますが、競技プログラミングの界隈ではレートの色が変わった際に色変記事と呼ばれるポエムを投稿して良いという風潮があります。

茶色になるまでにやってきた勉強方法、利用しているツール、一度の挫折の過程で気づいたマインドセットなどについて記載していきたいと思います。

私のように文系の方・周りのレベルの高さに挫折しかけている方など、どなたかの参考になればうれしいです。

参考:先人たちの色変記事

AtCoderって何?

AtCoderは競技プログラミングのサービスです。

出題されるお題に沿って、制限時間内に正確にコードを組むことを目指すようなコンテストなどを楽しめます。

AtCoderとは何か?始めるまでに何をすれば良いか?という方は、以下の記事をご覧ください。

drken(通称、けんちょん)という競プロの界隈で非常に有名な方が書いている記事です。

色変って何?何がそんなにうれしいの?

AtCoderはコンテストの成績によりレートが増減し、一定の値を超えることでユーザーに色がつきます。

以下表および画像はe869120様のレッドコーダーが教える、競プロ・AtCoder上達のガイドライン【初級編:競プロを始めよう】 - Qiitaより引用させていただいています。

レーティング 相対的な位置 絶対的な位置
2800+ 上位 0.2%
2400-2799 上位 0.6%
2000-2399 上位 2% アルゴリズムの研究職・研究開発で重宝されるレベル
1600-1999 上位 5% ほとんどのIT企業でアルゴリズム能力がカンストする
1200-1599 上位 10% 半数以上のIT企業でアルゴリズム能力がカンストする
800-1199 上位 20% エンジニアとしてかなり優秀
400-799 上位 35% 学生なら優秀
1-399 上位 100%

atcoder_colors

また、「絶対的な位置」の項目についてはAtCoder社長のchokudaiさんのブログをAtCoder(競技プログラミング)の色・ランクと実力評価、問題例 - chokudaiのブログをソースとしているとのことです。

下から2番目の段階で上位35%ですので、ここまで到達するまでにやめてしまう方が非常に多いと考えられます。

※ なお、AtCoder社監修の以下書籍では茶色で上位50%と表記されていますのでこちらの方が正しいのかもしれません。(単純なアクティブユーザーの中での順位か、真面目にコンテストに参加している人の中での順位の違いかと受け取っています)

筆者のバックグラウンド・レベル感

  • アラサー
  • 中学時代から数学が苦手で、大学も文系学部
  • 元公務員(6年)で、エンジニア歴は約3年半程度
  • 開発系の仕事を主にしてきたが、複雑なアルゴリズムの実装はなかった

アルゴリズム・数学的な素養があるわけではありません。

AtCoderはアルゴリズム力と数学的考察が非常に重要になるため、歴数年の職業エンジニアよりも数学が得意な未経験プログラマーのレートが高いということもザラにあると思っています。

そんな中、このような出自の私が茶色になれたのは、できる人からみたら大したことがなくても、私にとっては非常にうれしい変化ということになります。

勉強法の前に。自分の現段階のレベルを理解して適切な目標を定めましょう

私は2020年の末からAtCoderを開始して、2021年の3月に一度挫折しています。

zasetu_kikan

そもそも私がAtCoderを始めた理由は同僚エンジニア(今でも私のロールモデルになっている尊敬している方)が社内の部活のような集まりで同僚を誘っていたからです。

私の他、複数人のエンジニアがこれによりAtCoderを始めていました。

同時期にAtCoderを始めた非常に優秀なエンジニアもこの方法で学習していましたが、私がもたついている間にその方は2ヵ月くらいですぐに茶色コーダーになってしまいました。(以下Aさんと表記します)

エンジニア歴は変わらないのに、Aさんに比べて私はダメだ。競技プログラミングに向いていないんだ。」という自己嫌悪に陥りました。

以下のようなイメージでAtCoderを始めた訳です。

【当初のスタート地点の認識】

atcoder_miss_understanding

しかし、よく考えると職業エンジニアとしての経験は同じ程度でもAさんは以下のようなバックグラウンドを持っていました。

  • 九州でかなり有名な国公立大学の理系学部(情報系)卒業
  • CS(コンピュータサイエンス)を履修していた
  • 学生時代から数学が好きで、今でもたまに数学パズルを解いている

当たり前ですが、競技プログラミングに限らず皆さん歩んできた人生が異なり、研鑽してきた能力も学習してきた内容も全く異なります。

なぜか私は「エンジニア歴」という物差しで勝手に劣等感を感じていました。

逆に私は元公務員という経歴を持っていて、市役所勤務で言われてつらかったことで打線を組むことができます。これはAさんにはできないはずです。

ということで、以下の図のような考えに切り替えてコンテスト参加を再開したところ、勉強やコンテスト参加が楽しくなりました!

【スタート地点の認識修正後のイメージ】

atcoder_actual_start_line

もっと左を見れば多分こんな感じで、誰でも自分より上の人と比べるとつらそうだなと思っています。

atcoder_actual_start_line2

AtCoderの代表である高橋(chokudai)氏も以前このようにツイートされています。

【競プロの各色に対する認識オススメ】
・2色上は人外だと思うのが大切!比較しちゃだめ!1色上に追いついたところで人間に戻してあげよう!
・1色上は強い人!目標にするのは良いけど勝てなくて当たり前!いつかは追いつけたらいいなくらいに思おう!
・同色でも成長がヤバいやつはやっぱり人外!

— chokudai(高橋 直大)?@AtCoder社長 (@chokudai) June 29, 2020

そもそも「文系」「理系」というくくりも違う気がしますが、これから競技プログラミングを始める数学が苦手な方は人と比べず、自分のレベルにあった目標に向かっていけば精神衛生上よいかと思います!

高橋氏へのインタビューでもこのように発言されています。

当人のバックグラウンドによるので、自分の目標をきちんと定めることが大切ですね。

例えば、ガチガチの文系出身なら「茶色でも十分すごい」と言えますが、数学が得意という人ならもっと上を目指して欲しいです。

数回AtCoderに参加してみて、「自分がどのような問題まで解くことができるのか?」ということを把握して、解けない問題を少しずつ解けるようになることを目標にすると良いと思います。

ど文系が茶色になるまでにした勉強方法

数学・算数的な考え方のお勉強

いくつか問題を解いているうちに、数学というより算数的な考察力が足りていないと感じる様になりました。

とはいえ、現段階ではガッツリ受験数学の再勉強から始めることも続かないと思ったので、同じく文系出身のエンジニアからオススメしていただいた以下の本を読み直すことにしました。

「プログラマの数学 第2版」

この本は本当に読みやすく、勉強になりました。

難しい数式がなく平易な言葉で解説をしていただいています。

  • なぜ0乗は1と計算するのか
  • 割り算・剰余とは(グループ分け)

などなど、私がなんとなく流してきた分野を教えてくれて本当に面白く勉強になる書籍でした。

「東大の先生! 文系の私に超わかりやすく数学を教えてください!」

上記中学版と高校版の2冊です。

AtCoderの問題の中で三角関数やベクトルに関する問題が出ることもあったので、勉強のために購入しました。

この本を読んだ後に受験数学をやり直したわけではないので、何も見ないで問題を解くのは難しいのですが、考え方を理解できた気がします。

コンテスト中に「あっ。三角関数だ。余弦定理で検索しよう」と検索ワードが出てくるようになった気がします。

これら書籍のおかげで「知らない・わからない」という壁を超えて、「知っている。調べ方がわかる」まで行ける分野が増えたと思います。

数学が苦手な方にはオススメの書籍です!

B問題までを(ほぼ)確実に回答できるようにする学習

上記書籍を読んだ後は、AtCoder Beginner ContestのB問題までを(ほぼ)確実に解ける様に問題演習をしました。

演習にあたってはAtCoderProblemsというサービスを使って難易度が灰色のものを中心に解いていきました。

AtCoderProblemsは公式が提供しているわけではありませんが、公式サイトの便利リンク集にも掲載されています。

使い方などは調べれば先人の記事がたくさん出てくるので、ぜひ参考に見てください。

ちなみにB問題は過去問を解いている段階で解ける問題の方が圧倒的に多かったのですが、たまに難しいと感じる問題があり解けないこともありました。

実際茶色コーダーになるにあたって、B問題までは15分以内に解ける必要がありそうだったため、演習を続けました。

streaks

B問題の演習に関しては不要派・必要派と別れるかと思います。

私にとっては有用で、実際にC問題の難易度が高い回にはこの時に培った簡単な問題を早く解く能力に助けられました。

とはいえ、本質的には「難しい問題を解けるようになりたい」という思いがあったので、その前の準備段階としてとらえていました。

私にとって解けるか分からないのがC問題ですので、そこに全力を注ぐことができるようにしたかったわけです。

決してBまでは比較的簡単に解けるから無双気分を味わっていたわけではありません。

AtCoder Beginner Contestの過去問のB問題を8割程度時終わったので、次のステップに進みました。

競技プログラミング用の書籍を使った学習

「問題解決のための「アルゴリズム×数学」が基礎からしっかり身につく本」

タイトルからして私に必要そうな内容だったので購入させていただきました。

結論から言うと、とても良い本だったのですが、最初に読んだ時には内容をすべて理解できませんでした。

非常に平易な言葉で解説をしてくださっているのですが、この時はこの本の1章から3章と5章の前半の方を理解するので精いっぱいでした。

2週目・3週目と繰り返し、サンプルの問題を解いていくうちに理解が深まっていきました(すべての問題を解けたわけではありません)。

作者の米田優峻(E869120)氏は最近、「競技プログラミングの鉄則」という書籍を執筆されており、こちらも非常に良さそうですが、私はまだ読了できていません。

「アルゴリズム的思考力が身につく! プログラミングコンテストAtCoder入門」

この本について以前記事を書いています。

C問題を2回か3回のコンテストに1回解くことができる私にとって、ちょうど良い難易度の書籍でした。

この書籍には実際のAtCoderのコンテストで出題された問題を練習としてまとめてくださっています。

初回読む際には難易度(Difficulty)が400以下の問題を解きながら書籍を読み終えました。

2週目を読む際には難易度600以下、3週目は800以下という形で今の自分に合った難易度の問題のみを解いて回りました。

(できれば)C問題を回答できるようにする学習

ここまで終えて、やっとまともにC問題の演習を始めることにしました。

演習では引き続き、AtCoderProblemsを利用させていただきました。

Difficultyが400以下のものから順番に解いていき、20分考えても分からない問題は飛ばして解説を見るようにしました。

また、ABC100以前のC問題についてはDifficultyが700以下の問題でもチャレンジするようにしました。

実際の真偽はわかりませんが、過去の問題は最近のC問題に比べるとDifficultyが高めにでているような感覚を持っていて、実際解けることもあるためです。

下画像は再掲ですが、C問題を約5割程度解き終わっています。

streaks

結局はこの過去問をどれだけ理解しながら数をこなすかというのが一番重要で、結果に現れると感じています。

atcoder-cli というツールが神です

AtCoderを非常に便利に利用できるようになるツールです。

ojコマンドと連携することで、すばやくテストケースを試すこともできるようになるため、早く問題を提出することに大きく寄与してくれています。

使い方やインストール方法などについては、たくさんの先人の記事があるため省略させていただきます。

※ 他にも類似のツールがあるため、別のツールを使っている方もいらっしゃると思います。

実際以下のようにコンテストで利用しています。

  • コンテスト開始時
acc new abc○○○ #問題IDを入力

これにより `abc○○○``というディレクトリに問題や回答するためのテンプレートが配置されます。

# 例
abc268
├── a
│   ├── main.py
│   └── tests
│       ├── sample-1.in
│       ├── sample-1.out
│       ├── sample-2.in
│       └── sample-2.out
├── b
│   ├── main.py
│   └── tests
│       ├── sample-1.in
│       ├── sample-1.out
│       ├── sample-2.in
│       ├── sample-2.out
│       ├── sample-3.in
│       ├── sample-3.out
│       ├── sample-4.in
│       └── sample-4.out
├── c
│   ├── main.py
│   └── tests
│       ├── sample-1.in
│       ├── sample-1.out
│       ├── sample-2.in
│       ├── sample-2.out
│       ├── sample-3.in
│       └── sample-3.out
├── contest.acc.json
├── d
│   ├── main.py
│   └── tests
│       ├── sample-1.in
│       ├── sample-1.out
│       ├── sample-2.in
│       ├── sample-2.out
│       ├── sample-3.in
│       ├── sample-3.out
│       ├── sample-4.in
│       └── sample-4.out
├── e
│   ├── main.py
│   └── tests
│       ├── sample-1.in
│       ├── sample-1.out
│       ├── sample-2.in
│       ├── sample-2.out
│       ├── sample-3.in
│       └── sample-3.out
├── ex
│   ├── main.py
│   └── tests
│       ├── sample-1.in
│       ├── sample-1.out
│       ├── sample-2.in
│       ├── sample-2.out
│       ├── sample-3.in
│       └── sample-3.out
├── f
│   ├── main.py
│   └── tests
│       ├── sample-1.in
│       ├── sample-1.out
│       ├── sample-2.in
│       └── sample-2.out
└── g
    ├── main.py
    └── tests
        ├── sample-1.in
        ├── sample-1.out
        ├── sample-2.in
        └── sample-2.out

私の場合、Python3を利用して問題を解いているので、あらかじめ設定済みの main.py というファイルが設置されるにようになっています。

  • 問題に対する回答のコードを書いている時

コードを書き終えたらテストケースを確かめることができるように以下のように .zshrc にaliasを設定しています。

alias test='oj t -c "python3 main.py" -d ./tests/'

testコマンドをうつことで、サンプルのテストケースを通すことができるか確認します。

  • 回答のコードを書き終えた時

サンプルのテストケースが通り、自信ができたら以下コマンドで提出します。

# 提出したい問題のディレクトリ直下で以下コマンドを実行(C問題を提出したいならcディレクト直下)
acc s
# 提出して良いか確認が出るのでよければ指示通りに入力する

このコマンドのあと、ブラウザで提出の結果が表示されます。

atcoder_cli_submit

これでAC(正解)となれば次の問題に進む。

ということを繰り返していきます。

エディタの設定

私はneovimを用いてコーディングしています。

その際によく使うコードや、便利ライブラリとして持っておきたいコードはスニペット化しておくことをおすすめします。

たとえば私は以下のようなコードをスニペットとして持っていて、コマンドで呼び出せる様にしています。

# 入力をint型を要素とした配列として受け取る
l = list(map(int, input().split()))

このように配置しています。

持っておいた方が良いテンプレートは今後どんどん増やしていくつもりです。

まとめ

  • 一番大事なのは他人と比べすぎないこと
    • 近いレベルの方と切磋琢磨するのは良さそう
  • 自分のレベルを考え、背伸びしすぎないで過去問演習
  • 便利なツールは遠慮なく使う
  • エディタの機能も使う

以上です。

なお、弊社には私の狭い観測範囲でももっと高いレベルの方が所属していますので、私のレベルが弊社エンジニアのレベルということは断じてありません。

私も競技プログラミングにフルコミットはできませんが、私の目標である、とある北国のエンジニアに少しでも追いつけるようにマイペースに頑張りたいと思います。

とはいえ、あっさりと灰色に戻ることもあると思いますが、生暖かい目で見ていただきますようお願いします。

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.