はじめに
本記事はAdvent Calender 2021 「競技プログラミングを始めたばかりの人に伝えたいこと」の21日目の記事です。
2ヶ月前に競技プログラミングを始めたばかりの業プロerが、迷走しつつも自分なりに競技プログラミングと向き合った変遷を書いたものになります。
正直なところ、こんな初心者の一体験談を公開してなにになるのか?と不安でいっぱいです。
しかし、何事も始めた当初がもっとも大変なのにも関わらずその感情は月日が立つと忘れてしまうものかと思います。
始めたばかりの自分だからこそ、始めたばかりの人が抱くありのままの喜怒哀楽を伝えることができるかと思い、執筆させていただきました。
Qiita投稿は初めてのためお見苦しいところがあるかと存じますが、ご笑覧いただければ幸いです。
諸注意
- 本記事の「業務プログラミング」は、主にWeb系のシステム開発を指します
- 本記事の「競技プログラミング」は、AtCoder社様が主催するAtCoder Beginner Contest(ABC)のことを指します
自己紹介
あきくと申します。AtCoder ABCを始めて2ヶ月の競技プログラミング初心者です。
仕事では主にPythonとGoによるソフトウェア開発に取り組んでいます。いわゆる業プロerです。
私は文系のため情報科学が未履修のため、プログラミングの仕事をするうえで基本的な知識に不安がありました。
さらに最近になり教育指導の機会が増えた事情もあり、「そろそろ腰を据えて学ばないと。。。」と思っていたところ、本アドベントカレンダーの主催であるけんちょんさん(@drken)のQiita記事を拝読しました。
けんちょんさんのわかりやすくおもしろい文章とアルゴリズムが織りなす豊かな世界に、とたんに魅了されました。
そのけんちょんさんが競技プログラミングという分野でご活躍されていることを知って興味を持ち、今年の10月から取り組みはじめました。
競技プログラミングに対する誤解と理解
競技プログラミングを始める前の私は、競技プログラミングに対して楽観的な考えを持っていました。
競技プログラミングはプログラミングの一種なのだろうから、きっと業プロerは有利なのだろう、と。
残念ながら、そんなことは一切ありませんでした。
C問題の壁
私は数学にいたっては大学受験以降のおよそ15年間、勉強する機会がほとんどありませんでした。
私のように数学から離れてしまった社会人で、競技プログラミングを始めたばかりの方はきっと少なくないと思います。
そのような方の多くはきっとABCコンテストのC問題にぶつかると思います。
私は思いっきりC問題の壁にぶつかりました(今現在もぶつかり続けています)。
例えば、以下のような問題です。
コンテストでも練習でもまったく手に負えないので、悔しさを通り越して怒りをもつこともありました。
「これ、プログラミングの問題というよりも受験数学なのでは??」
と思いました。恥ずかしい限りですが。。。
業務プログラミングと競技プログラミングは別物
いま振り返ると、競技プログラミングを始めた当初は「プログラミング」に固執していました。
業務も競技も同じ「プログラミング」だろうと。
しかし、C問題を解くには、より広く言うと競技プログラミングを楽しむためには、業務プログラミングと競技プログラミングの性質は想像以上に異なるという業プロerにとっては悲しい事実を受け入れる必要があります。
業プロer目線でC問題までに必要な技術を考えるとわかりやすいかもしれません。
C問題までに必要なプログラミングは「基本的な入出力・四則演算・条件分岐・繰り返し処理・ソート、あとPythonならリストと辞書、set」くらいです。
業プロerにとっては本当に初歩的なことかと存じます。
プログラミングスキルだけをみると、C問題を解く準備はできているはずです。
しかし、いくらプログラミングに時間をかけてもC問題は解けませんでした。
考察が主、プログラミングは従
競技プログラミングを始めて2週間が経ち、少しずつ競技プログラミングの取り組み方がわかってきました。
転機となったのは、プログラミングだけではC問題は解けないと気づいたことです。
それまで私は問題に取り掛かるとすぐにプログラミングを始めていました。
入力ケースを操作する中でどうやって出力ケースに合わせていくか、という方向性で取り組んでいました。
これは完全に業務プログラミングの思考法だと思います。
例えばサイコロをプログラミングで表現する場合を考えます。
この場合、サイコロは考察がさほど必要ないくらい仕様が定まっているので、テストケースを用いてうまく入出力を合わせれば仕様の通りにサイコロを実装できます。
隠された仕様を発掘せよ
一方で競技プログラミングの設問ではあえて仕様が隠されています。
なおかつその隠された仕様を明らかにするにはテストケースが少なすぎます。
そのため問題文の通りの仕様に則ってコーディングすると、得られる結果はTLE
かWA
になります。
つまり競技プログラミングにおいては考察によって隠された仕様を発掘するというのが必要不可欠になります。
私が考察の重要性に気づいたのは、公式解説のすぬけさんの動画を見ていたときでした。
例えば以下はABC223のC問題の解説動画になります。
すぬけさんの取り組みを見ると、まず初めに考察をして、十分に戦略を練った後にプログラミングをしています。
また、テストケースはプログラムにバグがないかを確認するために利用しているだけということもわかります。
考察を通して隠された仕様を発掘することで十分に一般性のある解法が立てられるため、どのようなテストケースにも対応できるということを意味していると思います。
このような考察第一、プログラミングはその次という取り組み方は、プログラミングが最優先になっていた私にとって青天の霹靂でした。
考察によって競技プログラミングにおもしろさを見いだす
考察に重点に置くようになってから、競技プログラミングに対する取り組み方が確実に変わりました。
プログラミングから問題を始めていた時期はほとんど問題文の仕様通りをするだけだったので、「ACかそうでないか」の2択しかありませんでした。
結果としてほとんど解けず、解説を見てもまったくわからない状況で、そのたびに落ち込んでいました。
しかし考察を意識するようになってから、解けない問題に対する向き合い方に変化が生まれました。
私にとって感慨深い問題となった次の問題を例にいたします。
(以下、当問題の考察を含みます。)
この問題は3段階にわたる考察が必要です。
- 素直に総乗を求める → TLE
- 以前の総乗を前学期の点数で割り、今学期の点数を掛ける → TLE
- 前学期と今学期の点数の大小を比較する → AC
私はACこそできませんでしたが、2段階目まで考察を進めることができました。
このとき、ACできない悔しさよりも、考察を深めることができた喜びのほうが大きいことに気がつきました。
それからは解けない問題に対して考察の方向性は解説と合っていたかまたはどのくらい深くまで考察ができたのかといった観点で向き合うことができるようになりました。
そして考察がある程度合っていれば部分点を得ることができたと考えるようになりました。
考察を通して部分点を得ることで成長を実感しやすくなり、格段に競技プログラミングを楽しめるようになりました。
なお、この問題を解くあたって@u2dayoさんの記事を参考にいたしました。
毎回ABCのすばらしい解説記事を投稿してくださり、初心者にとってこれほどありがたいことはありません。御礼申し上げます。
数学と向き合う
さて、考察の重要性にようやく気がついたのは良いものの、競技プログラミングを始めて1ヶ月が経ってもC問題は解けませんでした。
このころにはC問題を解くためには考察に加えて数学が必要だとわかってきました。
ただ、私にとっては考察以上に数学が大きな壁として立ち塞がっていました。
「素因数分解」や「余りの周期性」を用いる設問がでると、知識がないので手も足も出ない。。。という状況でした。
その時の私は「最大公倍数」や「約数」といった用語もわからないくらいの数学力でした。
あまりに数学ができず、一方で学ぶこともせず、「仕事の役に立たないから」といった的はずれな言い訳でなんとかプライドを保とうとしていました。
そんなときに、アルゴ式を始めたことと、きりみんちゃんさんの取り組みを知ったことが、私にとって非常に大きな転機になりました。
アルゴ式は最高の教材
アルゴ式は本アドベントカレンダーでも必ずと言ってよいほど紹介されている教育コンテンツです。
私も心の底からおすすめいたします。
もしアルゴ式がなかったら、C問題に打ちのめされて競技プログラミングを諦めていたと思います。
競技プログラミングで「二分探索」や「動的計画法」といった有名なアルゴリズムが出てくるのは、通常D問題以降になります。
そのため、私のようにC問題でつまずいていると花形の有名アルゴリズムを使う機会がなく、なかなか学習が進みません。
そんな折にアルゴ式を通してアルゴリズムを学ぶ機会をいただき、**「いつかアルゴ式で学んだ知識を使ってD問題を解きたい!」****「そのためにもC問題を攻略したい!」**という動機を得ることができました。
また、アルゴ式には整数論的アルゴリズムといった章があり、私にとって鬼門である「最大公約数の求め方」や「約数の個数」といった整数問題にも触れることができました。
アルゴ式に取り組むことで競技プログラミングに対する動機づけと学習の方向性が得られたことは大きな収穫でした。
この他にもアルゴ式のすばらしさは枚挙にいとまがないのですが、もう一点、非常に感銘を受けたことがございます。
それは解説が懇切丁寧に、初学者の目線で書かれているところです。
アルゴ式のコンテンツは算数から本格的なアルゴリズムまでとても幅が広いのですが、どれも微に入り細を穿つようなすばらしい解説がございます。
例えば下記の解説です。
私は「具体的な50個の10の倍数」の解説があることに心を打たれました。
私のように具体的なイメージが沸かないと理解が追いつかない人もいると思います。
そのような人に対しても教え導いてくれる、アルゴ式の懐の深さを感じました。
このようなすばらしいコンテンツを提供してくださっているsakさん@sakofsukenとけんちょんさんには、感謝の言葉もございません。
きりみんちゃんさんに感銘を受け、心を入れ替える
アルゴ式を通して整数問題を学ぶことができたのは大きな転機でした。
しかしアルゴ式だけでは取り組める問題が限られることがあり、問題数を重ねる必要性を感じました。
そのためにはもちろん数学に時間を割く必要があるのですが、私の矮小なプライドがなかなか許しませんでした。
いろいろな言い訳をいっては体裁を保ったふりをしていました。
(↑ 実装問題だったら解けるよ!と強がっているだけです。)
しかし、その実は「自分の数学力のなさを直視するのが恥ずかしい」というのが本心でした。
「解けないのが恥ずかしい」という気持ちを隠すために「"プログラマー"が競技プログラミングの問題が解けないのは問題がおかしい」という的はずれな思いになっていました。
(逆恨みも甚だしいですが、始めたばかりなので何もわかっていない状況だったのでお許しください…)
そんななか、ひとつの記事が私にとってこの2ヶ月での最大の転機となりました。
バーチャル幼女プログラマーのきりみんちゃんさんの、「義務教育の算数、数学を1から独学で勉強してみた話」です。
「義務教育を受けていない」という私よりもよほど困難な状況で、算数・数学を始めから学ぶという想像しがたいほどに困難な取り組みを完走されておりました。
目が覚めるほどの衝撃をうけました。
数学ができないことに対して言い訳ばかりしている自分が恥ずかしくなり、きりみんちゃんさんを見習って数学と向き合いたい、と思うようになりました。
そして競技プログラミングを始めて2ヶ月目に、ようやく数学を勉強する決意を固めました。
まだ勉強を始めて1週間くらいなのでなにも言えることはありませんが、業プロerにとっての快適な心理領域から抜け出して、ようやく競技プログラミングのスタート地点に立ったような気がしています。
きりみんちゃんさんには競技プログラミングの向き合い方だけではなく、学びに対する姿勢そのものを教えていただきました。
心から尊敬しております。
おわりに
競技プログラミングを始めたばかりの業プロerが競技プログラミングのスタート地点に立つまで変遷をたどった記事となりました。
ただのポエムとなってしまい、お目汚しを失礼いたしました。
競技プログラミングを始めたばかりの方にとって参考になることがひとつでもあれば望外の喜びです。
最後に、改めまして本アドベントカレンダーご主催のけんちょんさんに感謝いたします。
けんちょんさんのおかげで競技プログラミングの世界を知り、久しぶりに熱く没頭する日々を送ることができています。
この場をお借りして、深く御礼申し上げます。
さて、明日(22日目)のご担当は@square1001さんです。
本日(21日目)と明日(22日目)は本アドベントカレンダーの連続する2日間において、執筆者のレート差が最大となる組み合わせとなります。
明日が待ち遠しいですね!
最後までご覧いただき、誠にありがとうございました!!