【AtCoder】普通の人である私が緑になるまでにしたこと

こんにちは、[Kota](https://twitter.com/kota0501_orca)です。
ご閲覧いただきありがとうございます！

昨日開催されました[AtCoder Beginner Contest 176](https://atcoder.jp/contests/abc176)でレーティングが緑になりました！

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">ついに！入緑しました！！！<br>ここまで長かったのでめちゃくちゃ嬉しい😄<br><br>kota0501さんのAtCoder Beginner Contest 176での成績：1754位<br>パフォーマンス：1241相当<br>レーティング：754→815 (+61) :)<br>Highestを更新し、6 級になりました！<a href="https://twitter.com/hashtag/AtCoder?src=hash&amp;ref_src=twsrc%5Etfw">#AtCoder</a> <a href="https://twitter.com/hashtag/ABC176?src=hash&amp;ref_src=twsrc%5Etfw">#ABC176</a> <a href="https://t.co/ONTPDcUzzV">https://t.co/ONTPDcUzzV</a> <a href="https://t.co/jQKX7gwBsa">pic.twitter.com/jQKX7gwBsa</a></p>&mdash; Kota (@kota0501_orca) <a href="https://twitter.com/kota0501_orca/status/1297174679350738951?ref_src=twsrc%5Etfw">August 22, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


# 要約
- 競プロ開始してから**7ヶ月弱で緑**になったよ！
- この界隈は**人外**な人が多いよ！(人外についての説明は記事内で！)
- だから普通の人である私が緑になるまでに**したこと&していないこと**をまとめるよ！


# 1. はじめに

競技プログラミング(競プロ)は、2020年1月12日に初コンテストに出場し、そこから取り組んでいきました。
そして、始めてから昨日(2020年8月22日)のコンテストまでの**7ヶ月弱**で、レーティングが**緑(800-1199)**になりました。
この章で、レート感についてと、期間についてを所感として書いておきます。

### レート感
緑レートのレベル感については、chokudaiさん(AtCoder社 社長)が以下のようにまとめてくれています。(2020年8月23日時点)

>緑色　(Cランク R800~1199　上位30%)
緑色になれれば、「競技プログラミングに熱心に取り組んでいる人」と考えて問題ないでしょう。要求レベルも決して低くなく、出場回数が足りないとマイナス補正がかかるため、運だけで到達することはまず出来ないラインです。他社アルゴリズム力判定サービスだと、上位１％の最高ランクが付く実力です。（あくまで「アルゴリズム力部分だけであることに注意してください）

>印象としては、

>- 学生ならかなり優秀。
- エンジニアとしてもある程度の安心感がある。論理的に複雑な処理の実装に対応できない、なんてことはなさそう、くらいには思える。データ量が多い現場など、計算量の多い処理が要求される現場でなければ、このレート帯以上を求める必要はほぼない。

>くらいの印象です。もちろんアルゴリズム力しか計ってないので個人差があります。

>技術的な部分では、

>- if、forはもちろん、それを組み合わせて2次元配列に対して操作をしたり、深さ優先探索や幅優先探索などのキューや再帰を使った実装も出来る。
- 簡単な動的計画法の問題や、数学的に工夫する問題など、計算量の工夫も出来始める。   

>という感じです。

>[AtCoder（競技プログラミング）の色・ランクと実力評価、問題例](http://chokudai.hatenablog.com/entry/2019/02/11/155904)

このレベル感については、賛否両論あるようですが、今回は関係がないので割愛します。

このレベル感を見て、どう思うかは人によると思いますが、普通の人である私は、

「少しプログラミングはやったことあるし、競プロ自体に慣れればすぐに到達できそう！
if, for, 2次元配列って書いてあるし、そのくらいなら分かる！」

と思いました。(都合が良い部分だけを読み取った結果です。)

結論を言うと、この認識はかなり間違っていたと今は痛感しています。
上の認識だと、レート200-300(灰色)が良いところだと思います。

### 期間
競プロを開始してから緑になるまでの期間の7ヶ月弱についてですが、この界隈では決して早くはありません。

chokudaiさんが以下のように言及しているので「人外」というワードを使いますが、成長速度が異常な「人外」がとても多いです。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">【競プロの各色に対する認識オススメ】<br>・２色上は人外だと思うのが大切！比較しちゃだめ！１色上に追いついたところで人間に戻してあげよう！<br>・１色上は強い人！目標にするのは良いけど勝てなくて当たり前！いつかは追いつけたらいいなくらいに思おう！<br>・同色でも成長がヤバいやつはやっぱり人外！</p>&mdash; chokudai(高橋 直大)🍆🎪🐦 (@chokudai) <a href="https://twitter.com/chokudai/status/1277503196684943361?ref_src=twsrc%5Etfw">June 29, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

観測した範囲だけでこのような人外がいました。(人外度昇順)

- 1ヶ月で緑レート到達
- 半年で青レート到達
- 1回のコンテストで水レート到達


これらは人外度が高い人をピックアップしているのですが、これらとはインパクトが弱いものの十分に人外な人だらけです。
特にTwitterではこういった人が目立つため、「これが普通なのかー。」と最初は勘違いしてしまいます。
そして、どうしても比較していまい、「なんで自分は…。」と思うところまでがワンセットです。

そのため、普通の人である私が、一般的(?)な期間で緑レートになるまでにしたことと、連呼している私(普通の人)のスペックを書いていきます。


### 記事の構成

記事の構成はこのようになってます。
少し長いですが読んでいただけると嬉しいです！

1. [はじめに](https://qiita.com/Kota-Y/items/396ab3c57830dad65cfb#1-%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB)
    2. [レート感](https://qiita.com/Kota-Y/items/396ab3c57830dad65cfb#%E3%83%AC%E3%83%BC%E3%83%88%E6%84%9F)
    3. [期間](https://qiita.com/Kota-Y/items/396ab3c57830dad65cfb#%E6%9C%9F%E9%96%93)
    4. [記事の構成](https://qiita.com/Kota-Y/items/396ab3c57830dad65cfb#%E8%A8%98%E4%BA%8B%E3%81%AE%E6%A7%8B%E6%88%90)
2. [普通の人である私のスペック](https://qiita.com/Kota-Y/items/396ab3c57830dad65cfb#2-%E6%99%AE%E9%80%9A%E3%81%AE%E4%BA%BA%E3%81%A7%E3%81%82%E3%82%8B%E7%A7%81%E3%81%AE%E3%82%B9%E3%83%9A%E3%83%83%E3%82%AF)
3. [緑になるまでにしたこと&していないこと](https://qiita.com/Kota-Y/items/396ab3c57830dad65cfb#3-%E7%B7%91%E3%81%AB%E3%81%AA%E3%82%8B%E3%81%BE%E3%81%A7%E3%81%AB%E3%81%97%E3%81%9F%E3%81%93%E3%81%A8%E3%81%97%E3%81%A6%E3%81%84%E3%81%AA%E3%81%84%E3%81%93%E3%81%A8)
    1. [緑になるまでにしたこと](https://qiita.com/Kota-Y/items/396ab3c57830dad65cfb#31-%E7%B7%91%E3%81%AB%E3%81%AA%E3%82%8B%E3%81%BE%E3%81%A7%E3%81%AB%E3%81%97%E3%81%9F%E3%81%93%E3%81%A8)
    2. [緑になるまでにしていないこと](https://qiita.com/Kota-Y/items/396ab3c57830dad65cfb#32-%E7%B7%91%E3%81%AB%E3%81%AA%E3%82%8B%E3%81%BE%E3%81%A7%E3%81%AB%E3%81%97%E3%81%A6%E3%81%84%E3%81%AA%E3%81%84%E3%81%93%E3%81%A8)
4. [学んだアルゴリズムとデータ構造](https://qiita.com/Kota-Y/items/396ab3c57830dad65cfb#4-%E5%AD%A6%E3%82%93%E3%81%A0%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0%E3%81%A8%E3%83%87%E3%83%BC%E3%82%BF%E6%A7%8B%E9%80%A0)
5. [持ってるライブラリ](https://qiita.com/Kota-Y/items/396ab3c57830dad65cfb#5-%E6%8C%81%E3%81%A3%E3%81%A6%E3%82%8B%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA)
    6. [複数の数の最大公約数・最小公倍数](https://qiita.com/Kota-Y/items/396ab3c57830dad65cfb#%E8%A4%87%E6%95%B0%E3%81%AE%E6%95%B0%E3%81%AE%E6%9C%80%E5%A4%A7%E5%85%AC%E7%B4%84%E6%95%B0%E6%9C%80%E5%B0%8F%E5%85%AC%E5%80%8D%E6%95%B0)
    8. [約数列挙](https://qiita.com/Kota-Y/items/396ab3c57830dad65cfb#%E7%B4%84%E6%95%B0%E5%88%97%E6%8C%99)
    9. [素因数分解](https://qiita.com/Kota-Y/items/396ab3c57830dad65cfb#%E7%B4%A0%E5%9B%A0%E6%95%B0%E5%88%86%E8%A7%A3)
    10. [MOD用組み合わせ](https://qiita.com/Kota-Y/items/396ab3c57830dad65cfb#mod%E7%94%A8%E7%B5%84%E3%81%BF%E5%90%88%E3%82%8F%E3%81%9B)
    11. [Union-Find木](https://qiita.com/Kota-Y/items/396ab3c57830dad65cfb#union-find%E6%9C%A8)
6. [使っているスニペット](https://qiita.com/Kota-Y/items/396ab3c57830dad65cfb#6-%E4%BD%BF%E3%81%A3%E3%81%A6%E3%81%84%E3%82%8B%E3%82%B9%E3%83%8B%E3%83%9A%E3%83%83%E3%83%88)
7. [おわりに](https://qiita.com/Kota-Y/items/396ab3c57830dad65cfb#7-%E3%81%8A%E3%82%8F%E3%82%8A%E3%81%AB)
8. [よく勉強に利用させていただいたサイト](https://qiita.com/Kota-Y/items/396ab3c57830dad65cfb#8-%E3%82%88%E3%81%8F%E5%8B%89%E5%BC%B7%E3%81%AB%E5%88%A9%E7%94%A8%E3%81%95%E3%81%9B%E3%81%A6%E3%81%84%E3%81%9F%E3%81%A0%E3%81%84%E3%81%9F%E3%82%B5%E3%82%A4%E3%83%88)


# 2. 普通の人である私のスペック
前提として、普通の人というのは定量的に測れるものではありません。

しかし、

「普通の人？どうせよくいる強い人なのでは？」

と思われてしまうのも嫌なので簡単にですが、私のスペックを書きます。

- 新卒1年目のWebエンジニア(ここ2ヶ月間で書いたコードは0行)
- 地方国立大学学部卒
    - 高専からの3年次編入なのでセンター数学経験なし
- 基本情報技術者試験を取得
- データ分析用途でPythonは使ったことがある(AtCoderではPython(PyPy)を使用している)

要するに競プロで大事である、高校数学のちゃんとした勉強経験がないということです。
これを見てどう感じ取るかも人それぞれですが、競プロ界隈では間違いなく上位ではないです。
逆にプログラミング自体は高専に通っていたこともあり、早めに始めたことから、総合的にみて特段に低いとも思っていないため、普通の人と言わせてもらっています。

# 3. 緑になるまでにしたこと&していないこと

次に、そんな普通の人である私が緑レートになるまでにしたことを書いていきます。
また、していないことを書かれた記事がほぼなかったのでそちらも書きたいと思います。

## 3.1. 緑になるまでにしたこと

したことは次のようなことです。

- 毎日AC
- 高校数学の勉強
- Twitter

次からはこれらのしたことの詳細を書いていきます。

### 毎日AC

[AtCoder Problems](https://kenkoooo.com/atcoder/#/table/)でStreakが見れるので毎日ACすることを日課にしてます。

簡単な問題を埋める、いわゆる虚無埋めをやってしまいがちなのですが、それでも解かない日があるよりかはましと思って解いてます。(習慣化することが大事！)

Current Streakは、Unique ACがカウント対象と知らずに途中で切れました。
違う解法で解き直したら見事に切れてしまいました。笑
みなさんも気をつけてください！

ここから記念にぺたぺた貼っていきます。

#### Achievement

![スクリーンショット 2020-08-23 5.55.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202993/10a1d4a2-745f-cd69-7734-dce0fbee1427.png)


#### Difficulty Pies

![スクリーンショット 2020-08-23 5.54.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202993/46daa016-2bad-f5a5-7132-d060a3bd7172.png)


#### Climbing -Colored-

![スクリーンショット 2020-08-23 5.53.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202993/e897afb7-3aad-8136-dcf8-2e38d82ddb47.png)

#### Heatmap -Max Difficulty- 

![スクリーンショット 2020-08-23 5.54.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202993/cf273cda-84fe-35de-492a-2b63040e35a9.png)


あと、GitHubに競プロでUnique ACしたものを毎日定時に自動PUSHするようにしています。
精進によって草が生えていくため、モチベーションにもなるのでおすすめです！

![スクリーンショット 2020-08-23 5.57.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202993/b6841b44-c4e0-5441-8e57-5ed75febe82f.png)


### 高校数学の勉強

[高校数学の美しい物語](https://mathtrain.jp/)のサイトで勉強しました。

私的には難しいものが多いので飛ばし飛ばしで読んでいますが、様々な発見もあり面白いのでおすすめです。

これからも少しずつ読み進めていきたいと思います。

### Twitter

競プロは継続、つまりモチベーション維持が大切です。
そのため、モチベーション維持のためにTwitterアカウントを作成するというのがよくなされています。

疑心暗鬼な気持ちで始めてみましたが大成功でした！

本界隈は、人外が多いのも事実なのですが、優しい人(⊇人外)がとても多いです。
様々なところで分からないところを教えあったり、励ましあったりしています。

人によるとは思いますが、一人で黙々と精進するよりかは誰かと一緒に精進した方が精神的にも良いためおすすめです！

[私のTwitterアカウント](https://twitter.com/kota0501_orca)

↑よければ、私のTwitterアカウントもフォローお願いします！一緒に精進していきましょう！

## 3.2. 緑になるまでにしていないこと

していないことは次のようなことです。

- 蟻本などの競プロ本購入
- バチャコン参加
- 外部コンテスト参加

次からはこれらのしていないことの詳細を書いていきます。

### 蟻本などの競プロ本購入

よく見るこの本のことです。
![ari.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202993/beeccd5d-6b95-3e3e-ae62-92ba96aa39d5.jpeg)

他にもchokudaiさんが著者のチーター本と呼ばれる競プロ本もあります。

アルゴリズムについての情報はネット上に有志の方がきれいにまとめてくださっているので購入していないです。
有志の方がまとめてくださっているよく勉強で使用させていただいたサイトについては、記事の最後でまとめています。
あと、私がPython(PyPy)を使用しているという理由もあります。(蟻本は参考実装がC++らしいので)


### バチャコン参加

[AtCoder Problems](https://kenkoooo.com/atcoder/#/table/)でよくバチャコンと呼ばれるバーチャルコンテストが開催されています。

くじかつと呼ばれるものはほぼ毎日開催されているようです。

レーティングに反映されないこともあり、まとまった時間をとることが厳しいため参加していないです。

### 外部コンテスト参加

この[Codeforces](https://codeforces.com/)という海外コンテストに参加されている方が多いです。

参加してみたいとは思っているのですが、海外のコンテストなので時間が不規則かつ健康的な時間に開催していないことが多いので避けてしまっています。

ただコンテストへの参加は、モチベーションを保つ上で大事なことだと感じているので、可能であれば積極的に参加した方が良いと思います。


# 4. 学んだアルゴリズムとデータ構造

学んだアルゴリズムとデータ構造について書いていきます。
また、学んだはいいものの緑になる上でコンテストでは使わなかったものは明記したいと思います。
そして、その上で緑になる上での重要度を独断と偏見で書きます！

| 名前 | 使った(○)・使っていない(×) | 重要度(高・中・低) |
|:-:|:-:|:-:|
| bit全探索  | ○ | 高 |
| 二分探索  | ○ | 高 |
| 累積和  | ○  | 高 |
| 約数全列挙  | ○ | 高 |
| 素因数分解  | ○  | 高 |
| GCD・LCM | ○  | 高 |
| 貪欲法  | ○  | 中  |
| 幅優先探索(BFS)  | × | 中 |
| 深さ優先探索(DFS)  | × | 中 |
| imos法  | ×  | 低 |
| 動的計画法(DP)  | ×  | 低 |
| 優先度付きキュー  | ×  | 低 |
| グラフアルゴリズム | ×  | 低 |
| ダブリング | ×  | 低 |
| Union-Find Tree | ×  | 低 |

こう見ると必要なのは、典型的なアルゴリズムスキルより、素早く正確な考察力だと分かります。
もちろん様々なアルゴリズムを使いこなせた方が良いのは間違いないと思いますが、緑になるだけならそこまで多くのアルゴリズムを学ばなくても良さそうです。

# 5. 持ってるライブラリ
ライブラリというまでのものではありませんが、保存しているものを貼っておきます。
よく使うものは、すぐにコピペできるところに置いておくのが良いと思ってます！

### 複数の数の最大公約数・最小公倍数
```Python
from functools import reduce

# 最大公約数
def gcd_list(num_list: list) -> int:
    return reduce(gcd, num_list)

# 最小公倍数
def lcm_base(x: int, y: int) -> int:
    return (x * y) // gcd(x, y)
def lcm_list(num_list: list):
    return reduce(lcm_base, num_list, 1)
```

### 約数列挙
```Python
def make_divisors(n: int) -> list:
    return_list = []
    for i in range(1, int(n**0.5)+1):
        if n % i == 0:
            return_list.append(i)
            if i != n // i:
                return_list.append(n//i)

    return return_list
```

### 素因数分解
```Python
def prime_factorize(n: int) -> list:
    return_list = []
    while n % 2 == 0:
        return_list.append(2)
        n //= 2
    f = 3
    while f * f <= n:
        if n % f == 0:
            return_list.append(f)
            n //= f
        else:
            f += 2
    if n != 1:
        return_list.append(n)
    return return_list
```

### MOD用組み合わせ
```Python
def mod_cmb(n: int, k: int, p: int) -> int:
    if n < 0 or k < 0 or n < k: return 0
    if n == 0 or k == 0: return 1
    if (k > n - k):
        return mod_cmb(n, n - k, p)
    c = d = 1
    for i in range(k):
        c *= (n - i)
        d *= (k - i)
        c %= p
        d %= p
    return c * pow(d, p - 2, p) % p
```

### Union-Find木
```Python
class UnionFind:
    # 作りたい要素数nで初期化
    # 使用するインスタンス変数の初期化
    def __init__(self, n):
        self.n = n
        # root[x]<0ならそのノードが根かつその値が木の要素数
        # rootノードでその木の要素数を記録する
        self.root = [-1]*(n+1)
        # 木をくっつける時にアンバランスにならないように調整する
        self.rank = [0]*(n+1)

    # ノードxのrootノードを見つける
    def findRoot(self, x):
        if(self.root[x] < 0): # 根
            return x
        else:
            # ここで代入しておくことで、後の繰り返しを避ける
            self.root[x] = self.findRoot(self.root[x])
            return self.root[x]
    # 木の併合、入力は併合したい各ノード
    def unite(self, x, y):
        # 入力ノードのrootノードを見つける
        x = self.findRoot(x)
        y = self.findRoot(y)
        # すでに同じ木に属していた場合
        if x == y:
            return 
        # 違う木に属していた場合rankを見てくっつける方を決める
        if self.rank[x] > self.rank[y]:
            self.root[x] += self.root[y]
            self.root[y] = x

        else:
            self.root[y] += self.root[x]
            self.root[x] = y
            # rnkが同じ（深さに差がない場合）は1増やす
            if self.rank[x] == self.rank[y]:
                self.rank[y] += 1
    # xとyが同じグループに属するか判断
    def isSameGroup(self, x, y):
        return self.findRoot(x) == self.findRoot(y)

    # ノードxが属する木のサイズを返す
    def count(self, x):
        return -self.root[self.findRoot(x)]
```


# 6. 使っているスニペット
あまりスニペットが共有されているところは見ないので、需要があるかは分かりませんが貼っておきます。
ABCではどうしても解く速度がとても重要になっている現状があるので、自身にあったスニペットは必須だと思っています。

```python:submit.py
import sys, re
from math import ceil, floor, sqrt, pi, factorial, gcd
from copy import deepcopy
from collections import Counter, deque
from heapq import heapify, heappop, heappush
from itertools import accumulate, product, combinations, combinations_with_replacement
from bisect import bisect, bisect_left, bisect_right
from functools import reduce
from decimal import Decimal, getcontext
# input = sys.stdin.readline 
def i_input(): return int(input())
def i_map(): return map(int, input().split())
def i_list(): return list(i_map())
def i_row(N): return [i_input() for _ in range(N)]
def i_row_list(N): return [i_list() for _ in range(N)]
def s_input(): return input()
def s_map(): return input().split()
def s_list(): return list(s_map())
def s_row(N): return [s_input for _ in range(N)]
def s_row_str(N): return [s_list() for _ in range(N)]
def s_row_list(N): return [list(s_input()) for _ in range(N)]
def lcm(a, b): return a * b // gcd(a, b)
sys.setrecursionlimit(10 ** 6)
INF = float('inf')
MOD = 10 ** 9 + 7
num_list = []
str_list = []

def main():
    n = i_input()
    a, b = i_map()
    num_list = i_list()

    print()

if __name__ == '__main__':
    main()

```

# 7. おわりに

以上、普通の人である私が緑になるまでにしたことでした！
微力ですが同じく普通の人の力になれば嬉しいです！

ここまで長い文章となりましたが、読んでいただきありがとうございました。
質問やアドバイス等ありましたらコメントしていただけると喜びます！

次は水色を目指して精進していきます！

ありがとうございました！

# 8. よく勉強に利用させていただいたサイト

- [AtCoder Problems](https://kenkoooo.com/atcoder/#/table/)
- [AtCoder に登録したら次にやること ～ これだけ解けば十分闘える！過去問精選 10 問 ～](https://qiita.com/drken/items/fd4e5e3630d0f5859067)
- [レッドコーダーが教える、競プロ・AtCoder上達のガイドライン【中級編：目指せ水色コーダー！】](https://qiita.com/e869120/items/eb50fdaece12be418faa)
- [アルゴリズムロジック](https://algo-logic.info/how-to-think-cp/)
- [競技プロ的なアルゴリズムのスライドのまとめ](https://yukicoder.me/wiki/slide)