競プロ典型90問☆4ざっくりメモ

競プロ典型90問

https://atcoder.jp/contests/typical90

☆4はatcoder problems Difficultyが800 ~ 1199、ABC換算だと400点問題(D問題)レベルらしい。 とりあえず全部やったので雑にメモ+振り返り

  1. https://atcoder.jp/contests/typical90/tasks/typical90_a
答え 最大の長さを求める問題から長さXを作れるかという判定問題に

二分探索
欲しい値の取りうる範囲が大きい場合、それをlog(n)で出せる方法。

欲しい値がちょうど条件の境界線にある場合に有効。

ex.最大の中の最小値,条件を満たす中での最大値

そのようなケースは数列の単調増加(減少)がある場合に見られる。数列ではなく、実数上でも有効


  1. https://atcoder.jp/contests/typical90/tasks/typical90_c
答え

木の直径を求め、そこから最大の閉路を求める。

木の直径は以下の手順で求める。

1.任意の頂点から一番深い頂点をdfsで求める。それをuとする。

2.uからもう一度dfsし、uから一番深い頂点をvとする。

3.uからvまでのパスが木の直径


  1. https://atcoder.jp/contests/typical90/tasks/typical90_h
答え

ナップサック問題

各状態の個数を持っておきDP

この場合は{“a”,“at”,“atc”,…}のように文字をpushした時点での状態(個数)を保持


  1. https://atcoder.jp/contests/typical90/tasks/typical90_l
答え

UnionFind

赤マスの連結状態をチェック

グリッド上での操作をグラフとしてみる。

たどり着ける=>2端点は同じ連結成分


  1. https://atcoder.jp/contests/typical90/tasks/typical90_z
答え

どの頂点も隣り合わない=>二部グラフ

二部グラフを生成し、N/2より多いグループの頂点をN/2個出力

二部グラフの特徴は奇数閉路を持たないこと。

木は二部グラフ


  1. https://atcoder.jp/contests/typical90/tasks/typical90_ab
答え

imos法

+….-..
……..
……..
-….+..

左から右への累積のあと、上から下への累積


  1. https://atcoder.jp/contests/typical90/tasks/typical90_ah
答え

尺取法

実装詰まりがち

とりあえず、半開区間を[l,r)として定義し、lをfor文で回しながらrをできるだけ右に持っていくような実装にする。


  1. https://atcoder.jp/contests/typical90/tasks/typical90_ap
答え

メモ化再帰orDP

DPだとO(k^2)になると勘違いしてた。


  1. https://atcoder.jp/contests/typical90/tasks/typical90_aq
答え

単純にBFSでやるとまずい

例えば、vからuへの経路でくねくねしてる短い道と真っ直ぐの多い遠回りな道の2つがあるとする。

頂点を一度しか調べない単純なbfsをした場合、uに先にたどり着くのは前者の経路であるが、実際は後者が最適経路。

ダイクストラ法を用いる。

priority_queueで方向転換回数が少ないものを優先的に取り出す。

前述の例だと遠回りでも後者が先にuにたどり着いて最小コストを記録できる。

拡張BFSでデータの持ち方を工夫しても出来るらしい。

この場合、各頂点にどちらの方向を向いてるかの状態を保持させるといい。

グリッド上での探索問題は様々なケースを考慮した上で最適なアルゴリズムやデータの持ち方を選択することが重要


  1. https://atcoder.jp/contests/typical90/tasks/typical90_bf
答え

ボタンを2^x回押した時の今表示されている数字の遷移先を考える。2^x回の遷移先は2^(x-1)の遷移を2回行ったものであることがポイント。

この情報はx<=60まで見て記録すればいい。

あとは、Kの立っているbitに応じて2^x回押した時の遷移先を参照していけば、最終的にK回押した時の数字の遷移になるはず

同じ処理を10^18回ほど繰り返す問題は大体bitごとに考えるのがいい気がする。

もしくは、二倍ずつや半分ずつにするような反復処理を考えて、その中に何か法則性がないかを模索するのが良い。

Kがとんでもなくでかい数字だったら通用しない

想定解答は周期性を見つけるとのこと


  1. https://atcoder.jp/contests/typical90/tasks/typical90_bk
答え

bit全探索

明らかにHが少ないことに気づけば解ける。

全探索のうちの1つに着目して、問題を簡略化する。

この場合、同じ数字で構成された列の個数のうち、一番多かった列の個数を求める。


  1. https://atcoder.jp/contests/typical90/tasks/typical90_br
答え

x,yは独立に考えることが出来る。

マンハッタン距離の総和が最小となる点は中央値


  1. https://atcoder.jp/contests/typical90/tasks/typical90_bt
答え

すべての経路を再現する。バックトラック

再帰関数を用いる。

関数に潜る前にvisitedをtrueに、帰ってきたらfalseにする。

visited[{ny,nx}]=true;

dfs({ny,nx},visited);

visited[{ny,nx}]=false;


  1. https://atcoder.jp/contests/typical90/tasks/typical90_cg
答え

約数の個数を記録

その中でfor文を回す。

約数の個数が少ないことに気づけるかどうか

例2^32=>33個、10^12=>13*13=169個


振り返り

各問題の応用にあたった時の解法ひらめき力と実装力をそれぞれ10点満点で評価すると

  1. 二分探索、決め打ち二分探索(8,8)
  2. 木の直径(6,8)
  3. ナップサック問題(5,6)
  4. UnionFind(9,10)
  5. 木、二部グラフ(6,8)
  6. imos法(8,6)
  7. 尺取法(9,5)
  8. DP(7,7)
  9. 拡張BFS,ダイクストラ(5,5)
  10. 周期性(7,5)
  11. bit全探索(10,10)
  12. マンハッタン距離の総和(6,9)
  13. バックトラック(7,6)
  14. 約数列挙(7,7)

これらをすべてやってみて、以下の点が今の自分に足りないと感じた。

  • ダイクストラ法や拡張BFSの応用力や実装力
  • 区間問題になると実装が詰まる
  • 整数問題は様々なアプローチを考えてしまい、最適な解法にすぐたどり着かない。
  • 再帰で考える問題はバグらせがち

とはいえ、やっててあまり苦戦しなかったからこれからは応用力をつけるように精進する。
あと実装力や早解き力も上げたい。(多分これがネック)
ABCの過去問で緑パフォを安定して出せるぐらいになったら典型☆5に取り組む。