初心者がC#でAtCoderデビューするためのVSProjectテンプレート

この記事は [NSSOL Advent Calendar 2019](https://qiita.com/advent-calendar/2019/nssol) の4日目の記事です。

# TL;DR
https://github.com/sekikatsu36/AtCoder
↑こちらをfork

# 概要
この記事では「**C#使いの競技プログラミング未経験者が、C#で初AtCoderに挑むハードルを下げる**」ことを目的に、ベースとなるVSプロジェクトの共有＆紹介を行います。

コンテストを続けるための便利TIPSは他にも山ほどあるので、気になればぜひ調べててみてください。（末尾に参考URLを記載）

# 背景
AtCoderはいわゆる競技プログラミングコンテストのサービスです。
今更ですが、私も最近AtCoderを始めまして。（まだ茶色レベルの新米です）
初回にC# + Visual Studioで参戦した際、「事前にVSプロジェクトとか準備した方がいいんだろうなぁ」と思ってはいたのですが、それを怠って**ぶっつけ本番**で突撃して見事なまでに**惨敗**。

何度か再戦し、最近それっぽいプロジェクトが出来上がったので、この場を借りて共有します。
「競プロをC#で！」みたいな記事は世に溢れてますが、VSプロジェクトは転がっていないようだったので、この期に配布。
私のような悔しい思いをする方が一人でも減ればと。


# なんでC#？

**C#が好きだから**

その一言に尽きるんじゃないでしょうか。

一応上げると、以下のようなメリットがあります。

- LINQが便利（ただしOrderByは使ってはならぬ。遅すぎ）
- Visual Studioが神IDE
- ジェネリックが使える

ただ、ぶっちゃけ、AtCoderでワザワザC#を選ぶ必要はないです。
C#には以下のようなデメリットがあるので、PythonやC++が得意ならそっちの方が良いと思います。

- 競プロで便利なコレクション操作の一部が標準装備されていない(vs Python)
- 遅い (vs C++)
- 人口が少ない

# できあがったもの
以下にあります。
適宜forkしてください。

https://github.com/sekikatsu36/AtCoder

# 使い方

A～Fまで、すべての問題が一プロジェクトに収まってるので、masterからブランチを切れば即コンテストを始められます。
ライブラリを作りたいときは、それ用のクラスを適当に追加すれば良いので、管理は楽だと思います。

コンテスト中にエントリクラスやライブラリに変更を加えた際は、そのファイルだけmasterにmergeすれば次のコンテストですぐ使えます。

```
git checkout abc146 -- .\AtCoder\Program.cs
```

問題を切り替えるときはProgram.cs内で呼び出すクラスを書き換える必要があります。
そこはイケてないのですが、良い方法が思いつかず。
まぁ何かしらの方法で切り替える必要はあると思うので、今はこれで妥協してます。
妙案あったらシェアいただけると嬉しいです。


# 中身の紹介

## 無限ループで繰り返し実行できる

まぁ言うまでもなく。
これくらいパパっと実装できるとは思いますが、事前に用意してあるとストレスが全然違います。
初心者が一番最初に欲しくなる機能だと思います。

## スタートアップオブジェクトを指定して、コピペで提出できるようにする

すべての問題をそのまま一プロジェクトにまとめると、エントリポイントの問題が出てきます。
そのまま各問のクラスにMainメソッドを追加すると「エントリポイントが複数定義されてるぞ」とVisual Studioの怒りを買ってしまいます。
かといって、Main以外の名前にしてしまうと、コードをコピペして提出した時にAtCoderから「エントリポイントが見つからない」と心無いことを言われてしまいます。
プロジェクトを分けるのもコードを共通化しにくい。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299048/8d6196e1-f42b-ae6b-ed19-0c0e975e25cc.png)

そんな時はプロジェクトのプロパティから**[アプリケーション]>[スタートアップオブジェクト]を設定**しましょう。
複数のクラスでMainメソッドが定義されていても、これを指定すれば普通に実行できます。

## 各問の最初によくつかう標準入力処理を書いておく

AtCoderは、テストケースを標準入力から受け取る仕様です。
競プロ勢からすれば標準入出力なんて手慣れたものでしょうが、初心者は一瞬手が止まると思います。（標準入力とか普段使わないし）
出鼻を挫かれるのも何なので、最初から載せておきます。実際の問題に合わせて、追加・削除します。

```C#
// 文字列の入力
string s = Console.ReadLine();

// 整数の入力
long n = long.Parse(Console.ReadLine());

// 文字列配列の入力
string[] inputStrArray = Console.ReadLine().Split(' ');

// 整数配列の入力
long[] inputLongArray = Console.ReadLine().Split(' ').Select(i => long.Parse(i)).ToArray();
```

ちなみに、intを使ってメモリをケチる必要はないです。
これまで10回弱参加しましたが、メモリが問題になったことはほぼなかったので。
予期せぬ桁溢れの方がずっと怖いので、脳みそを止めてlongを使います。（メモリは溢れてから考えるスタイル）

なお、「入力を高速化」みたいなTIPSも世には転がってますが、最初はそこまで神経質になる必要はないかな、と。

## 各問の最後に標準出力処理を書いておく

AtCoderは、結果を標準出力から返す仕様です。
入力同様、出力処理も記載しておきます。

C#のConsole.WriteLineは遅いので、Mainの開始時にAutoFlushをfalseにセットして、

```C#
var sw = new System.IO.StreamWriter(Console.OpenStandardOutput()) { AutoFlush = false };
Console.SetOut(sw);
```

最後にFlush処理を行います。

```C#
Console.Out.Flush();
```

こうすれば少しだけ高速化できます。（と偉い人が言っていた。自分で速度計測したわけではないです orz）
結果の出力をFlushの前に書くことだけ意識的に。

## オーバーフローを例外化する

初心者がやらかすミスの一つがオーバーフロー（桁溢れ）だと思います。
私も何度も痛い目を見ました。

前項の通りintを使わないことである程度回避できますが、それでも食らうときは食らうので、ローカル環境ではオーバーフローが発生したら例外が出るようにしましょう。
プロジェクトのプロパティで、[ビルド]>[詳細設計]>[演算のオーバーフロー及びアンダーフローのチェック]をONにします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299048/1f0b7934-df5e-4c06-557f-528f98a41be5.png)

## ライブラリを用意しておく（任意）

ライブラリを持っておくと、解くスピードがぐっと上がる可能性があります。
が、個人的に、

- 事前に揃えておいても、初心者はどうせ使いどころが分からない
- 一度自分で実装しようとしてみた方が勉強になる

という理由から、特にはじめは意識しなくてもいいと思います。

とはいえ、C#でAtCoderをやっていれば、今に以下のようなライブラリが欲しくなってくると思うので、「欲しいな」と思ったタイミングでライブラリ化しましょう。

- 優先度付きキュー。合わせてダイクストラも。
- UpperBound, LowerBound
- gcd（最大公約数）
- 素因数分解
- nCr

使うときはLibを直接呼び出すのではなく、各問のクラスにコピペするよう注意。

# その他TIPS

他にも、以下のようなことをやっておくと、便利かもしれません

- コードスニペットを覚えておく https://qiita.com/Kosen-amai/items/248e44dff958be901a84
    - for/foreach/cwはよく使います
    - 他にもほしいものがあれば、Visual Studioを使っている利点をフル活用して、事前登録しておくよろし 
- 問題のURLを控えておく
    - コンテスト開始時はアクセスが集中するのでページ表示が遅いです
    - 問題の一覧 → A問題表示、と画面遷移すると若干待たされるので、最初からA問題に飛べるリンクを用意しておくと気が楽です（その数秒を争うレベルなのか？という疑問は捨て置く）
    - e.g. https://atcoder.jp/contests/abc141/tasks/abc141_a

# 参考リンク
- https://emkcsharp.hatenablog.com/entry/2013/Advent
- https://qiita.com/Camypaper/items/de6d576fe5513743a50e