別解がある競技プログラミング(AtCoder)の問題を集めてみた


# 初めに

　本記事は競技プログラミングで有名なatcoderの問題の中から、別解がある問題たちの一部を集めた記事です。
　　ある程度の勉強時間を競技プログラミングに充てると、問題を見た際に一瞬で解法が浮かんでしまう状況がよくあります(たとえばAtcoderBeginnerContestの序盤の早解きなどがその例)。もちろん、一瞬で問題状況を把握して素早く処理することは素晴らしいことですが、それだと思考停止して問題を解いただけであり、いずれはレートが上がらない状況に陥ってしまいます。当然、手元でサンプルを考えて法則性をつかむような思考力が要求される問題では通用しません。
  　また、個人的には水色コーダ中盤(レート1400ぐらい)からは1問からどれだけ学べるかが重要だと思ってます。(といいつつ筆者はこの記事公開当時(2024年５月)レート1200付近で停滞しています。)1つの問題をいろいろな見方で解けるようにすることで思考力が鍛えられます。並行して、より計算量を落とすテクニックや、知らなかったアルゴリズムを知ることができるきっかけにもなるためおすすめです.
　　掲載されている問題は全てABC(Atcoder Beginner Contest)からの出題です。難易度順に並んでいるとは限らないので、解けない問題の場合は、解法を見て復習することをお勧めします。
　atcoder界隈ではまだまだ弱いほうなので拙い部分等があるかもしれませんがご容赦ください。載せられている別解では実装例がない解説もあるため、解説に相当した実装コード(全てC++によるソースコード)をつけています。 

# 問題

- [ABC348E](https://atcoder.jp/contests/abc348/tasks/abc348_e)
    1. 重心を用いた解法(すぬけさんの解説はこの方針)
    ある頂点$v$に注目した際に$f(v)$の値がより小さくなる方向へ移動することをくりかえすといずれ$v$は重心になる。[提出コード](https://atcoder.jp/contests/abc348/submissions/52920252)
    2. 全方位木DPによる解法。
    $val[v]$=$v$の部分木の重みの合計。 
    頂点が$to$へ移る時に、コストの変化は$+(sumC-val[to])-val[to]$になる
     本番中にこちらの方針で解きました。[提出コード](https://atcoder.jp/contests/abc348/submissions/52098250)


- [ABC347D](https://atcoder.jp/contests/abc347/tasks/abc347_d)
    数学的な要素が強いと思います。
    1.桁DPとDPの復元 本番中にこの方法を思いつきました　[提出コード](https://atcoder.jp/contests/abc347/submissions/53028741)
    2.各桁で(0,1)のうち、何が許されるかを考える。二進数の性質をうまく使う。[MMNMMさんの解説](https://atcoder.jp/contests/abc347/editorial/9675)　
    [提出コード](https://atcoder.jp/contests/abc347/submissions/53029873)

- [ABC331E](https://atcoder.jp/contests/abc331/tasks/abc331_e)
    1. 片方を固定して全探索　[提出コード](https://atcoder.jp/contests/abc331/submissions/52986076)
    2. priority queueを用いた解法(公式解説)[提出コード](https://atcoder.jp/contests/abc331/submissions/52998844)
    3. 二分探索を用いた解法 [提出コード](https://atcoder.jp/contests/abc331/submissions/48141408)
    4. セグ木を用いた解法.setでの[提出コード](https://atcoder.jp/contests/abc331/submissions/52999176)
　いずれの解法もLの制約が小さいことをうまく利用します. たかだかL+1回目には食べ合わせのよいペアが出てくるため,Lを主役にした全探索をうまく思いつき,なにかしらのテクニック(二分探索やセグ木)を用いて高速化がポイントになります.
 

- [ABC329E](https://atcoder.jp/contests/abc329/tasks)
    1. 逆から操作する解法(すぬけさんの解説はこの方法を使用)[提出コード](https://atcoder.jp/contests/abc329/submissions/52954235)
    2. DPでの解法.本番中に思いつきたかった.(shiomusubi496さんの[解説](https://atcoder.jp/contests/abc329/editorial/7734)) 
    [提出コード1](https://atcoder.jp/contests/abc329/submissions/52980670)　[提出コード2](https://atcoder.jp/contests/abc329/submissions/47734458)

- [ABC326D](https://atcoder.jp/contests/abc326/tasks/abc326_d)
    方針はどちらも全探索ですが、実装の大変さが異なります
    - 1 [physics0523の解法](https://atcoder.jp/contests/abc326/editorial/7539)。再帰を用いた全探索とbitを用いてフラグを保持するというテクニックの組み合わせです。[コードにコメントした提出コード](https://atcoder.jp/contests/abc326/submissions/52293168)
    - 2 すぬけさんの解法です。制約をうまく用いることで、探索すべき箇所を小さくします。 1と比べて実装が格段に楽です$O((N!)^3 \times N^2)$ [提出コード](https://atcoder.jp/contests/abc326/submissions/53156789)


- [ABC323D](https://atcoder.jp/contests/abc323/tasks/abc323_d)
    - 1 二進数を用いた解法([公式解説](https://atcoder.jp/contests/abc323/editorial/7348)の一つ目) この考え方ができるようなりたいです.[提出コード](https://atcoder.jp/contests/abc323/submissions/52918317)
    - 2 愚直シミュレーション(公式解説の補足のほう)[提出コード](https://atcoder.jp/contests/abc323/submissions/52915322)

- [ABC315E](https://atcoder.jp/contests/abc315/tasks/abc315_e)
    典型のトポロジカルソートです。トポロジカルソートを解くアルゴリズムは2パターンの方針があります。
    - DFS　再帰を用いた解法 [提出コード](https://atcoder.jp/contests/abc315/submissions/52278625)
    - BFS 幅優先探索 [提出コード](https://atcoder.jp/contests/abc315/submissions/52278345)

- [ABC312C](https://atcoder.jp/contests/abc312/tasks/abc312_c)
    - 1 二分探索 [提出コード](https://atcoder.jp/contests/abc312/submissions/52538759)
    - 2 ソートを用いた解法 [提出コード](https://atcoder.jp/contests/abc312/submissions/52541793)

- [ABC311E](https://atcoder.jp/contests/abc311/tasks/abc311_e)
    1と2のどちらも公式解説参照
    - 1 二分探索 $O(HWlog(HW))$ [提出コード](https://atcoder.jp/contests/abc311/submissions/52039798)
    - 2 1を高速化したものです$O(HW)$ [提出コード](https://atcoder.jp/contests/abc311/submissions/52042610)

- [ABC310D](https://atcoder.jp/contests/abc310/tasks/abc310_d)
    どちらも[公式解説](https://atcoder.jp/contests/abc310/editorial/6783)に載っています。
    - 1 bitDPを用いた解法。私が本番中に思いついたのはこの方針です。 
    計算量$O(3^N TN)$[提出コード](https://atcoder.jp/contests/abc310/submissions/52277071)
    - 2 再帰を用いる解法 計算量$O(N! \times N)$ [提出コード](https://atcoder.jp/contests/abc310/submissions/52655452)

- [ABC308E](https://atcoder.jp/contests/abc308/tasks/abc308_e)
    - 1 累積和をもちいた解法(yuto1115さんによる公式解説は[こちら](https://atcoder.jp/contests/abc308/editorial/6708)) [提出コード](https://atcoder.jp/contests/abc308/submissions/53069736)
    - 2 {MEX} $\times${0,1,2}で分けた後に、Eを固定して二分探索　[提出コード](https://atcoder.jp/contests/abc308/submissions/52639537) 
- [ABC307E](https://atcoder.jp/contests/abc307/tasks/abc307_e)
    - 1 包助原理 kyopro_friendsさんによる公式解説 [提出コード](https://atcoder.jp/contests/abc307/submissions/52640123)
    - 2 円環DP　本番中に思いついたのはこの方針です。 [提出コード](https://atcoder.jp/contests/abc307/submissions/42934304)
    - 3 漸化式を作る. [MMNMMさんによる解説](https://atcoder.jp/contests/adt_hard_20240131_3/editorial/6656) [提出コード](https://atcoder.jp/contests/abc307/submissions/53068672)
    
- [ABC300F](https://atcoder.jp/contests/abc300/tasks/abc300_f)
    - 1 二分探索　[けんちょんさんの記事](https://drken1215.hatenablog.com/entry/2023/05/03/002258)を参考。　
    [提出コード1](https://atcoder.jp/contests/abc300/submissions/53076127)
    [提出コード2](https://atcoder.jp/contests/abc300/submissions/53076315)
    - 2 尺取り法 (すぬけさんの解説はこちらの方針)
    [提出コード](https://atcoder.jp/contests/abc300/submissions/49771976) 
    
- [ABC296E](https://atcoder.jp/contests/abc296/tasks/abc296_e) 
    - 1 DAG。再帰でサイクルを見つけます [提出コード](https://atcoder.jp/contests/abc296/submissions/53045108)
    - 2 ダブリング([shakayamiさんの解法](https://atcoder.jp/contests/abc296/editorial/6135))[提出コード](https://atcoder.jp/contests/abc296/submissions/53051215)
    - 3 強連結成分分解 ([evimaさんの解法](https://atcoder.jp/contests/abc296/editorial/6118))[提出コード](https://atcoder.jp/contests/abc296/submissions/53051625)

- [ABC292C](https://atcoder.jp/contests/abc292/tasks/abc292_c)
    [けんちょんさんの解説](https://drken1215.hatenablog.com/entry/2023/05/16/230900)
    - 1 $O(N√N)$の解法 [提出コード](https://atcoder.jp/contests/abc292/submissions/52656252)
    - 2 $O(NlogN)$の解法. 調和級数を用いて1の解法を高速化します [提出コード](https://atcoder.jp/contests/abc292/submissions/52657315)




- [ABC282F](https://atcoder.jp/contests/abc282/tasks/abc282_f) 
    1. スパーステーブルの解法 [提出コード](https://atcoder.jp/contests/abc282/submissions/52537317)
    2. 分割統治法の解法. (こちらは実装がすこし面倒)[提出コード](https://atcoder.jp/contests/abc282/submissions/52538391)
    どちらもsunukeさんのコード解説あり.

    
- [ABC271C](https://atcoder.jp/contests/abc271/tasks/abc271_c)
    以外と難しいと思います。本番中に解けませんでした。
    すぬけさんが解説しています。
    - 1 二分探索 [提出コード](https://atcoder.jp/contests/abc271/submissions/52181877)
    - 2 ハッシュマップ(c++ではsetなど)を用いた解法 [提出コード](https://atcoder.jp/contests/abc271/submissions/52182110)
    - 3 愚直シミュレーション（m_99さんによる公式解説）　[提出コード](https://atcoder.jp/contests/abc271/submissions/53073093)

- [ABC270E](https://atcoder.jp/contests/abc270/tasks/abc270_e) 
    1,2の両方の解法ができるようになりたいです.
    1. 何周でKを超えるかを考える. 周期を用いて高速に求める(すぬけさんの解説はこの方針)
    [提出コード](https://atcoder.jp/contests/abc270/submissions/52915002)
    2. 何周するかを二分探索して求める(kyopro_friendsさん解法)
    [提出コード](https://atcoder.jp/contests/abc270/submissions/52907582)
    
    2の解法は実装が簡単になるためおすすめです.二分探索手法を知っていても言われるまで思いつくことができませんでした.

- [ABC267E](https://atcoder.jp/contests/abc267/tasks/abc267_e)
    1. 二分探索「最大値の最小化」というキーワードなので決め打ちで考えると二分探索が思いつきます。 (公式解説)[提出コード](https://atcoder.jp/contests/abc267/submissions/52181269)
    2. 優先度付きQueue (kyopro_friendsさんの解法)[提出コード](https://atcoder.jp/contests/abc267/submissions/52180312)

- [ABC258E](https://atcoder.jp/contests/abc258/tasks/abc258_e)
    - 1 ダブリングを用いた解法(すぬけさんが解説しています) [提出コード](https://atcoder.jp/contests/abc258/submissions/52831696)
    - 2 周期を用いた解法 [方針が書かれた参考記事](https://zenn.dev/kiwamachan/articles/5521c4096f5b07). [提出コード](https://atcoder.jp/contests/abc258/submissions/48899046)
    周期がかかわるものはダブリングを使うという考えも取り入れたいです.



- [ABC256F](https://atcoder.jp/contests/abc256/tasks/abc256_f)
  - 1 遅延セグメント木 ([potato167さんの解法](https://atcoder.jp/contests/abc256/editorial/4148))[提出コード](https://atcoder.jp/contests/abc256/submissions/53049300)
  - 2 セグメント木 ([kyopro_friendsさんの解法](https://atcoder.jp/contests/abc256/editorial/4131) すぬけさんによる解法もこの方法)
  [提出コード](https://atcoder.jp/contests/abc256/submissions/53047775)


- [ABC249D](https://atcoder.jp/contests/abc249/tasks/abc249_d)
    $M=\max(A_{i})$とする。$M \leq 2 \times 10^5$であることがポイントになります。
    - 1 $O(M √M)$[この解説](https://kazun-kyopro.hatenablog.com/entry/ABC/249/D)の解法1. 個人的には思いつきやすい解説です
    [提出コード](https://atcoder.jp/contests/abc249/submissions/53068821)
    - 2 $O(MlogM)$ [公式解説](https://atcoder.jp/contests/abc249/editorial/3786)はこちらを用いています 
    [提出コード](https://atcoder.jp/contests/abc249/submissions/53069209)


- [ABC247E](https://atcoder.jp/contests/abc247/tasks/abc247_e)
    要素がY以上,X以下のみからなる数列へAを分断します.各々の数列考えたときに
    - 1 包助原理 $(Y \leq v \leq X) - (Y < v \leq X)-(Y \leq v < X) + (Y < v < X)$ 
    [提出コード](https://atcoder.jp/contests/abc247/submissions/52128185)
    - 2 尺取り法　[提出コード](https://atcoder.jp/contests/abc247/submissions/52121740) 



- [ABC238D](https://atcoder.jp/contests/abc238/tasks/abc238_d)
    - 1 xorとandがわかる形に持っていく([penguinmaさんの解説]())[提出コード](https://atcoder.jp/contests/abc238/submissions/52530949)
    - 2 x,yを2進数で表した際に各位の値が0か1かの$2^2$通りを調べる(すぬけさんの解説)[提出コード](https://atcoder.jp/contests/abc238/submissions/52530718)

- [ABC238G](https://atcoder.jp/contests/abc238/tasks/abc238_g) 
    1. Moのアルゴリズムによる解法 [提出コード](https://atcoder.jp/contests/abc238/submissions/52130024)
    2. ハッシュを用いた解法 [physics053さんの解説](https://atcoder.jp/contests/abc238/editorial/3358)
    [提出コード](https://atcoder.jp/contests/abc238/submissions/52131020)

- [ABC237D](https://atcoder.jp/contests/abc237/tasks/abc237_d)
    - 1 逆から見ていく[公式解説](https://atcoder.jp/contests/adt_hard_20240124_1/editorial/3319) [提出コード](https://atcoder.jp/contests/abc237/submissions/53065054)
    - 2 双方向リスト(c++の場合はlist)を用いて解く[cirno3153さんによる解法](https://atcoder.jp/contests/adt_hard_20240124_1/editorial/3345) 
[提出コード](https://atcoder.jp/contests/abc237/submissions/53065430)
    
- [ABC234D](https://atcoder.jp/contests/abc234/tasks/abc234_d)
    - 1 multisetを用いた解法$O(NlogK)$ [提出コード](https://atcoder.jp/contests/adt_hard_20231219_1/submissions/48659252)
    - 2 BIT(セグ木でも可)と二分探索を用いた解法.$O(Nlog^2N)$ [提出コード](https://atcoder.jp/contests/adt_hard_20231219_1/submissions/48659207)


- [ABC228D](https://atcoder.jp/contests/abc228/tasks)
    - 1 インデックスの集合(c++ならsetやmap)を用意し,2分探索で求める
    [提出コード](https://atcoder.jp/contests/abc228/submissions/52128845)
    - 2 経路圧縮を用いた解法(UnionFindでよく用いる)
    [提出コード](https://atcoder.jp/contests/abc228/submissions/52128767)

- [ABC217G](https://atcoder.jp/contests/abc217/tasks/abc217_g)
    - 1 包助原理、スターリング数を用いた解法.sunukeさんの解説はこちらを使用。数え上げに慣れていれば思いつきやすい方針だと思います。
    スターリング数については[けんちょんさんの記事](https://qiita.com/drken/items/f2ea4b58b0d21621bd51)を参照
    [提出コード](https://atcoder.jp/contests/abc217/submissions/52282614)
   
    - 2 dpを用いた解法. [kyopro_friendsさんの解説](https://atcoder.jp/contests/abc217/editorial/2390)。
    [提出コード(forループver)](https://atcoder.jp/contests/abc217/submissions/52283146)
    [提出コード(再帰ver)](https://atcoder.jp/contests/abc217/submissions/52283101)

- [ABC159F](https://atcoder.jp/contests/abc159/tasks/abc159_f)
ナップザックDPの派生
    1. ナップサックDPの状態に区間の情報を追加して考える
    [hamayanhamayanさんの解法](https://blog.hamayanhamayan.com/entry/2020/03/22/234317)
    耳DP ([けんちょんさんの記事](https://drken1215.hatenablog.com/entry/2020/03/22/224200)も参考になります)    
    [提出コード](https://atcoder.jp/contests/abc159/submissions/53067292)
    
    2. 多項式の掛け算の係数と考えが同じ
    すぬけさんの解説の前半　 [提出コード1](https://atcoder.jp/contests/abc159/submissions/53066486)
    すぬけさんの解説の後半 [maspyさんの解説](https://maspypy.com/atcoder-%e5%8f%82%e5%8a%a0%e6%84%9f%e6%83%b3-2019-03-22abc-159#toc3)と同じ。 [提出コード2](https://atcoder.jp/contests/abc159/submissions/53066926) 
   
- [ABC137D](https://atcoder.jp/contests/abc137/tasks/abc137_d)
    1. 制約が厳しいものから貪欲法、どうすれば正当な貪欲法に落とし込めるかが考えるポイントになります.(こちらが王道のやり方。すぬけさんが解説しています)
    [提出コード](https://atcoder.jp/contests/abc137/submissions/52907285)
    2. マトロイドの性質を用いる解法.[公式解説pdf](https://img.atcoder.jp/abc137/editorial.pdf)を参照.
    マトロイドであることが貪欲法の正当性を保証します.
    (マトロイドについてはけんちょんさんの[記事](https://drken1215.hatenablog.com/entry/20121212/1355280288)を参照)[提出コード](https://atcoder.jp/contests/abc137/submissions/51786476)
    <!-- https://qiita.com/ngtkana/items/ec9319619c41b1a77572 -->
     


# 最後に
この記事に掲載された問題を通して、みなさんの競プロのレベル向上に貢献できれば幸いです。今回掲載した問題達はごく一部なので、時間があれば第二弾を執筆するつもりです。ここまで読んでいただきありがとうございました。