ガチでやらない競技プログラミング

この記事は[奈良高専 Advent Calendar 2021](https://adventar.org/calendars/6833 "奈良高専 Advent Calendar 2021")，４日目の記事です．

身の回りに競技プログラミングをしている人が少ないなと思ったので僕がなぜ競技プログラミングをしているのか，その良さを伝えようと思います．
# 競技プログラミングとは
競技プログラミング（略して競プロ）は，「与えられた課題を解くためのプログラムを書く」という競技です．
競技なので当然参加者に優劣を付けるのですが，その判断材料には

- 提出されたプログラムの正しさ
- 正解までにかかった時間
- 不正解の数

などがあります．（大会の主催者によって様々です）

また，基本的にプログラムは標準入出力（コンソール）を使うように指定されます．

こうしてみると，学校から出されるプログラミングの課題も競技プログラミングに近いと言えます．~~締め切りという時間制限を超えると成績が下がったりしますし~~

競技プログラミングにはWebサイトから参加することができます．例を挙げると[AtCoder](https://atcoder.jp/ "AtCoder")や[paiza](https://paiza.jp/ "paiza")[^1]などがあります．
[^1]: 「競技」という感じではないですが広い意味では競技プログラミングと言えると思います．
# 「ガチでやらない」とは
競技プログラミングでは，問題文に書かれていることをそのまま書き起こしたプログラムや，愚直に解を片っ端から全部調べるようなプログラムを作っても不正解になる（実行時間が長すぎたり，正確に扱えないほど値が大きくなる）ということがよくあります．
そのような問題を解くには工夫が必要で，その工夫をパターン化したものが「アルゴリズム」や「データ構造」と言われるものです．
上で挙げた[AtCoder](https://atcoder.jp/ "AtCoder")で開催されているAtCoder Beginner Contestでは８問中２・３問目あたりからそのような問題が出題されるので，上位に入るにはアルゴリズムやデータ構造についての知識が必須となります．

...

**むずい！！！！**
**めんどくさい！！！**
**他で何の役に立つねん！！！**
※個人の感想です

アルゴリズムやデータ構造の種類数は膨大でその中からどれを使えば良いかすら分かりませんし，そもそも自分の知らないものが出てくることもあります．（とあるコンテストの解説を見ていたら，僕の知らないアルゴリズムが「非常に有名です」と説明されていて心をへし折られました）
僕は競技プログラミングを１年近くやってきましたが未だにAtCoder Beginner Contestでは８問中４問目を解けるかどうかというラインで，レーティングは下から２番目の階級にいます．
しかもExcellent[^2]なアルゴリズムやデータ構造はまず発想がぶっ飛んでるので直感的に理解するのが難しく，理解するだけで数時間を消費します．
[^2]: そのアルゴリズムやデータ構造を使うことで実行時間の大幅な短縮に繋がる
おまけにアルゴリズムやデータ構造が競技プログラミング以外の場所で活かせる場面は，今のところ僕の周りには意外と少ない印象です．そういった能力が活かせる分野があるのは知っていますが，大規模なデータを扱うなど，身近に感じられるものではありません．

...とここまで書いた通り競技プログラミングを「ガチで」やることを全員にオススメすることはできないです．僕はガチでやる方に片足突っ込んでますが，もともと競技プログラミングを始めたときはそんなつもりはなかったです．

じゃあガチでやらない競技プログラミングにはどんな魅力があるのか，僕がなぜ競技プログラミングを始めたのか．ここからが本題です．
# 競プロは敷居が低い
競技プログラミングはやるだけならとにかく簡単です．標準入出力と基礎的な文法がある程度分かればOKです．これぐらい簡単だから学校の課題は競技プログラミングの形式をとることが多いとも言えます．

例として実際に[AtCoder Beginner Contest 207](https://atcoder.jp/contests/abc207 "AtCoder Beginner Contest 207")で出題された[A - Repression](https://atcoder.jp/contests/abc207/tasks/abc207_a "A - Repression")という問題を見てみます．この問題は与えられた３つの整数のうちの２つの和としてありえる最大値を求めるという問題で，

- １番目・２番目に大きい値を求めて足す
- ３通りの和を全て試す
- １番小さい値を求めて３つの和から引く

などの解法が考えられます．どの解法を使っても解けますが，このコンテスト当時の僕は３つ目の解法を使って以下のプログラムを提出していました．

```java:Main.java
import java.util.Scanner;
final class Main {
	public static void main(String[] args) {
		final Scanner SCANNER = new Scanner(System.in);
		int answer = 0;
		int min = 100;
		for(int i = 0; i < 3; i++) {
			final int INPUT = SCANNER.nextInt();
			answer += INPUT;
			if(INPUT < min) {
				min = INPUT;
			}
		}
		answer -= min;
		System.out.println(answer);
	}
}
```

他の解法を採用したとしてもこれと同じく高々20行以下の簡単なプログラムになるので，プログラミングを少しやっていれば競技プログラミング未経験でも解けると思います．

また，よほど自分のレベルより上の問題でない限りは１問１問が軽いです．１問あたり１時間もかかりません．（１時間というと重たそうですがアプリケーション開発など他の分野で考えれば短く感じると思います）
# プログラミングに慣れるための競プロ
### 言語仕様や標準ライブラリ
プログラミング言語はそれぞれ様々な仕様（文法）や標準ライブラリ（最初から使えるクラスや関数）を持っています．多くの人は必要に応じてそれらをインターネット検索で調べていると思いますが，しばらく触っていないプログラミング言語のことはつい忘れてしまいます．
しかし定期的にプログラミングに触れておくことでそうした忘れが減り，あまり調べなくてもプログラミングができる「プログラミングに慣れた」状態になれます．

実際にプログラミングをしなくても普段から自主的に調べるようにすれば済むかもしれませんが，~~そんな習慣付けてる人本当にいるのか信じがたいですし，~~何を調べるべきかがはっきりしないと思います．
調べたい疑問点が浮かんでくるときというのは，

- 自分の欲しい機能が既に標準ライブラリにあるか探すとき
- プログラムが理解不能な挙動をしたとき
- 他のことを調べていて分からないところがあったとき

など，実際にプログラミングをしているときがほとんどになるので，やはり定期的にプログラミングに触れることは必要です．また，別に競技プログラミングでなくてもプログラミングであれば良いのですが，１問１問が軽いという特性上競技プログラミングはかなり向いていると思います．
### プログラミング的思考（？）
最近（？）巷でよく言われる「プログラミング的思考」という言葉，僕もよく分かっていないですが，「脳内世界をプログラムに変換する」という意味だと勝手に思ってますし，この記事ではそういう前提で書きます．

例えば上に載せた例題で「１番小さい値を求めて３つの和から引く」という解法がまず脳内に浮かんだとして，「１番小さい値を求める」は「暫定の最小値と各候補を比較して，必要であれば暫定の最小値を更新する」，「３つの和」は「３回for文を回して予め用意した変数に足していく」というようにプログラム的に変換できます[^3]．

プログラミング的思考のやり方は説明しづらく，習うより慣れろという感じなので身に付けるにはやはり定期的にプログラミングに触れることが必要で，競技プログラミングの出番となります．
また基本的に解説と解答例が用意されているので，解説を見て脳内世界にできた解法と解答例のプログラムを照らし合わせることで先人たち[^4]のプログラミング的思考を効率良く学ぶことができるというのも大きいです．
[^3]: これでも完全にプログラム的とは言えず，「暫定の最小値」を初期値100の変数とすることや，「各候補との比較」をfor文で行うことなどを考えないといけません．また，プログラムでは最小値の計算と和の計算を並行してやった方が良いです．
[^4]: 問題や解説を作っている人たちは競技プログラミングで最上位に入る化け物です．
# 競プロで旅行に行ける
競技プログラミングはオンライン上だけでなく，オフラインでも開催されています．新型コロナウイルスの感染拡大により，現在はそれなりに制限がかかっていますが，全国規模のものだと大会主催者や学校のお金で旅行に行くなんてことができます．
僕がこれまで参加したオフライン（だったはず）の大会は以下の通りです．

- [日本情報オリンピック](https://www.ioi-jp.org/joi/2021/index.html "第21回日本情報オリンピック")
    - コロナ禍以前は本選から先がオフライン開催でしたが，今年は本選もオンライン開催のようです
    - 本選で上位に入ると東京でトレーニング合宿というものに参加できるらしいです
    - トレーニング合宿で上位に入ると国際情報オリンピックという世界大会に出れるらしいです
    - 僕は２次予選で落ちました
- ぐんまプログラミングアワード
    - コロナ禍の中なんとかオフラインで開催してくれました
    - 競技を含めたイベントという感じで楽しかったです
- パソコン甲子園
    - コロナ禍以前は本選が会津大学（福島県）で開催されていましたが，去年・今年は本選もオンライン開催となりました．

### 競技プログラミング以外の部門でのオフライン大会
上で挙げた３つの大会のうち，下２つには競技プログラミングの部門以外にもモバイルアプリを作ってプレゼンする部門などがありますが，相当な時間をかけて努力した上で，熾烈な予選を勝ち抜いてきているという印象を受けました．
それに比べたら競技プログラミングは当日の一発勝負で決まるので事前の準備量というより普段の能力が問われるところが大きく，気軽に参加しやすいかなと思います．
# 最後に
これを機に競技プログラミングに触れ，プログラミングを楽しむ人が増えてくれれば幸いです．