競技プログラミングの鉄則 演習問題集(1~5章) - noko206/AtCoder GitHub Wiki

競技プログラミングの鉄則 演習問題集(1~5章)

これは何?

競技プログラミングの鉄則 演習問題集 の要点や感想をまとめたページです。

1章 アルゴリズムと計算量

$N^2$ を出力。

https://atcoder.jp/contests/tessoku-book/submissions/44137103

$A+B$ を出力。

https://atcoder.jp/contests/tessoku-book/submissions/44137181

配列 $A$ の中に $X$ があるかどうかを全探索。

https://atcoder.jp/contests/tessoku-book/submissions/44137220

$A$ から $B$ までの値に $100$ の約数があるかどうかを全探索。

https://atcoder.jp/contests/tessoku-book/submissions/44137280

$P,Q$ の組み合わせを全探索。

https://atcoder.jp/contests/tessoku-book/submissions/44137325

3つの組み合わせは3重ループで実装。

https://atcoder.jp/contests/tessoku-book/submissions/44137365

$N$$2$ で割った余りを文字列として末尾に結合していく。
長さが $10$ 未満なら $0$ をいくつか結合する。
最後に文字列を反転させて出力。

https://atcoder.jp/contests/tessoku-book/submissions/44137414

$N$ を文字列として受け取る。
$0$ で初期化した $ans$ に、 $ans *= 2$$ans += N_i$ を繰り返す。

https://atcoder.jp/contests/tessoku-book/submissions/44137474

2つだけ全探索して、残りの1個は $O(1)$ で求まるというやつ。
赤いカードに書く数字 $A$ と、青いカードに書く数字 $B$ を全探索して、
白いカードに書く数字 $C$$K-A-B$ として $O(1)$ で求める。
$C$$1 \le C$ かつ $C \le N$ を満たしていたら答えを+1。

https://atcoder.jp/contests/tessoku-book/submissions/44137533

2章 累積和

累積和で区間和を求めることで高速化する。

https://atcoder.jp/contests/tessoku-book/submissions/44137653

$l$ をデクリメントして半開区間として扱うと楽。
アタリの個数は $[l,r)$ の区間和に等しく、ハズレの個数は $r-l$ からアタリの個数を引いた数に等しい。

https://atcoder.jp/contests/tessoku-book/submissions/44137736

いもす法で区間加算を高速化する。

https://atcoder.jp/contests/tessoku-book/submissions/44137820

$[l,r)$ の区間だけ出勤していると考えればよい。
あとはいもす法で区間加算をする。

https://atcoder.jp/contests/tessoku-book/submissions/44137924

2次元累積和をする。

https://atcoder.jp/contests/tessoku-book/submissions/44138020

$X,Y$ の最大値が $1500$ なので、縦横 $1500$ で初期化した配列で累積和を求める。

https://atcoder.jp/contests/tessoku-book/submissions/44138124

2次元いもす法をする。

https://atcoder.jp/contests/tessoku-book/submissions/44138429

$A,B,C,D$ の最大値が $1500$ なので、縦横 $1500$ で初期化した配列でいもす法を求める。

https://atcoder.jp/contests/tessoku-book/submissions/44138593

RMQで通してごめんなさいになりました。

https://atcoder.jp/contests/tessoku-book/submissions/44138877

$[0,l)$$[r,n)$ の2つの区間に対する何らかの値を計算しておき、
それらを組み合わせて最適な値を求めるのはよく見かける手法。

先頭から見たときのMAXと、末尾から見たときのMAXをそれぞれ配列で管理しておけばよい。

https://atcoder.jp/contests/tessoku-book/submissions/44139111

3章 二分探索

二分探索をして $X=A_i$ となる $i$ を求める。

https://atcoder.jp/contests/tessoku-book/submissions/44139363

二分探索をして $X \ge A_i$ となる $i$ を求める。
配列の添え字は0-indexedなので、 $i$ がそのまま答えとなる。

https://atcoder.jp/contests/tessoku-book/submissions/44139459

答えで二分探索。
以下のような特徴があれば、答えで二分探索に該当すると思っている。

  • 単調性がある
  • 答えを決め打ったときに条件を満たしているかの判定が容易

https://atcoder.jp/contests/tessoku-book/submissions/44139602

小数で二分探索をするときは適当な回数ループを回す。

https://atcoder.jp/contests/tessoku-book/submissions/44139978

尺取り法をする。
以下のような問題であれば、尺取り法に該当すると思っている。

  • 「条件」を満たす区間 (連続する部分列) のうち、最小の長さを求めよ
  • 「条件」を満たす区間 (連続する部分列) のうち、最大の長さを求めよ
  • 「条件」を満たす区間 (連続する部分列) を数え上げよ

参考:https://qiita.com/drken/items/ecd1a472d3a0e7db8dce

添え字をバグらせたくないのでdequeで実装している。

https://atcoder.jp/contests/tessoku-book/submissions/44140221

尺取り法をする。

https://atcoder.jp/contests/tessoku-book/submissions/44140630

半分全列挙。
$A,B$ の組み合わせ $X_i$$C,D$ の組み合わせ $Y_i$ を事前に列挙しておく。
$Y$ をソートして、 $K-X_i$ と一致する値が $Y$ に存在するかを二分探索で判定する。

https://atcoder.jp/contests/tessoku-book/submissions/44140917

これぞ半分全列挙という感じ。
$A$ を半分に分割して、それぞれの組み合わせを列挙する。
片方をソートして条件を満たすものが存在するかを二分探索。

https://atcoder.jp/contests/tessoku-book/submissions/44141234

座標圧縮のライブラリをぺたり。

https://atcoder.jp/contests/tessoku-book/submissions/44141389

4章 動的計画法

DPをする。

  • $dp_i:=$ $i$ 番目の部屋にたどり着くまでの最短時間
  • $dp_0=0$

遷移は $A_i$ 分かかる通路か、 $B_i$ 分かかる通路のどちらを使うかの $2$ つを考える。

https://atcoder.jp/contests/tessoku-book/submissions/44161536

DPをする。

  • $dp_i:=$ 足場 $i$ に到達するまでに支払うコストの最小値
  • $dp_0=0$

遷移は足場 $i$ から足場 $i+1$ と足場 $i+2$ のどちらにジャンプするかの $2$ つを考える。

https://atcoder.jp/contests/tessoku-book/submissions/44161650

A16と同じ問題。ただ、DP復元をする必要がある。
添え字を後ろから見ていき、DP値の整合性が合うもの順に選んでいく。

https://atcoder.jp/contests/tessoku-book/submissions/44161765

B16と同じ問題。DP復元をする。

https://atcoder.jp/contests/tessoku-book/submissions/44161868

愚直にやると $O(2^N)$ かかる解法の計算量を改善できるのはDPの特徴の1つだと思う。

  • $dp[i][j]:=$ $i$ 番目までのカードを使用したときに合計を $j$ にできるかどうか

https://atcoder.jp/contests/tessoku-book/submissions/44206711

A18と同じ問題。DP復元をする。

https://atcoder.jp/contests/tessoku-book/submissions/44206956

ナップサックDPをする。

https://atcoder.jp/contests/tessoku-book/submissions/44207174

ナップサックDPの価値を状態に持つやつをやる。

https://atcoder.jp/contests/tessoku-book/submissions/44207398

LCSをやる。

https://atcoder.jp/contests/tessoku-book/submissions/44207571

★解説AC★

  • $dp[i][j]:=$ $S$$i$ 文字目までを $T$$j$ 文字目までに一致させるために必要な最小の操作回数
  • 削除: $chmin(dp[i+1][j+1], dp[i][j+1]+1)$
  • 挿入: $chmin(dp[i+1][j+1], dp[i+1][j]+1)$
  • 変更: $chmin(dp[i+1][j+1], dp[i][j]+$$s[i]==t[j]$$?0:1)$

LCSしてからどうこうを考えていたが、この問題自体がLCSのような遷移を考える問題になっていた。
遷移が与えられているのだから漸化式を立てるという発想になってほしい。

https://atcoder.jp/contests/tessoku-book/submissions/44212124

参考:https://o-treetree.hatenablog.com/entry/DPL1E

区間DPをする。

  • $dp[l][r]:=$ 区間 $[l,r]$ のブロックのときに得られる合計得点の最大値
  • $dp[l][r]=max(dp[l+1][r]+a[l], dp[l][r-1]+a[r])$
    • ただし、 $l+1 \le p[l]$ かつ $p[l] \le r$ でなければ $a[l]$ の代わりに $0$ を足す
    • ただし、 $l \le p[r]$ かつ $p[r] \le r-1$ でなければ $a[r]$ の代わりに $0$ を足す

https://atcoder.jp/contests/tessoku-book/submissions/44368178

【★解説AC★】

$dp[l][r] <- dp[l+1][r-1]$ の遷移は思いついたけど、
$dp[l][r] <- dp[l+1][r], dp[l][r-1]$ の遷移が思いつかなかった。

2次元DPは表にしたときの隣り合う3方向からの遷移を考えることが多いように感じるので、
迷ったらそれらの遷移を試してみる。

https://atcoder.jp/contests/tessoku-book/submissions/44368657

配るDPをする。
到達不可のマスからの遷移は考えないようにすること。(1WA)

https://atcoder.jp/contests/tessoku-book/submissions/44368939

配るDPをする。

https://atcoder.jp/contests/tessoku-book/submissions/44369105

あまり見たことない形式のbitDP。

  • $dp[bit]:=$ 購入した品物の集合が $bit$ のときの使用クーポンの最小枚数
  • $dp[bit|k]=max(dp[bit|k],dp[bit]+1)$
    • ただし、クーポン $i$ を使用して購入できる品物の集合を $k$ とする

https://atcoder.jp/contests/tessoku-book/submissions/44369347

よく見かける形式のbitDP。
巡回セールスマン問題を解く。

https://atcoder.jp/contests/tessoku-book/submissions/44369783

LISをする。
ライブラリをぺたり。

https://atcoder.jp/contests/tessoku-book/submissions/44388081

【★解説AC★】

$x_i$ が狭義単調増加のとき、 $y_i$ の最長増加部分列が答えになることはすぐにわかる。
$x_i$ が等しい $y_i$ について、 $y_i$ が最大となるものだけを採用して配列を作り直したがWA。
これだと $y_i$ が最大以外のものが使いたくなったときにうまくいかない。
$x_i$ が等しい場合に、同じ $x_i$$y_i$ を採用しないためには $y_i$ を降順にソートすればよい。

https://atcoder.jp/contests/tessoku-book/submissions/44389292

  • $dp[i][j]:=$ マス $(i,j)$ に到達するまでの通り数。
  • $dp[i][j]+=dp[i-1][j]+dp[i][j-1]$
    • ただし、 $c[i][j]=$ # なら更新は行わない。

https://atcoder.jp/contests/tessoku-book/submissions/44389490

5章 数学的問題

$O(\sqrt N)$ の素数判定をする。
ライブラリをぺたり。

https://atcoder.jp/contests/tessoku-book/submissions/44389732

エラトステネスの篩で素数列挙をする。
ライブラリをぺたり。

https://atcoder.jp/contests/tessoku-book/submissions/44389800

ユークリッドの互除法でGCDを計算する。
よく使うのでテンプレートに入れている。

https://atcoder.jp/contests/tessoku-book/submissions/44389866

ユークリッドの互除法でLCMを計算する。
$a,b$long longで受け取らないとオーバーフローするので注意。

https://atcoder.jp/contests/tessoku-book/submissions/44390081

modintで計算すると楽。

https://atcoder.jp/contests/tessoku-book/submissions/44390297

modintで計算すると楽。

https://atcoder.jp/contests/tessoku-book/submissions/44390410

繰り返し二乗法で累乗を計算する。
ACLのmod_powを使用すると楽。

https://atcoder.jp/contests/tessoku-book/submissions/44390473

上と同じ。

https://atcoder.jp/contests/tessoku-book/submissions/44390560

二項係数を求めるライブラリを作成した。

https://atcoder.jp/contests/tessoku-book/submissions/44391502

$h+w-2$$C$$w-1$ を計算する。

https://atcoder.jp/contests/tessoku-book/submissions/44392129

包除原理をする。
「3の倍数の個数」+「5の倍数の個数」-「15の倍数の個数」

https://atcoder.jp/contests/tessoku-book/submissions/44392230

bit全探索で包除原理をすると一般の場合でも解くことができる。

https://atcoder.jp/contests/tessoku-book/submissions/44392556

Grundy数を求めて $g[N]$$0$ なら後手必勝、そうでないなら先手必勝。

https://atcoder.jp/contests/tessoku-book/submissions/44451035

DPでもいける。

https://atcoder.jp/contests/tessoku-book/submissions/44451166

DPをする。

https://atcoder.jp/contests/tessoku-book/submissions/44451238

各山に対してGrundy数を求めてその論理和を取る。
山に $a_i$ 個の石があるとき、 $0$$a_i-1$ 個の石がある状態へ遷移可能なので $g[a_i]=a_i$ となる。

https://atcoder.jp/contests/tessoku-book/submissions/44451316

【★解説AC★】

縦方向と横方向の移動はそれぞれ独立に考えられるので、
$2N$ 個の山があるNimととらえることができる。

https://atcoder.jp/contests/tessoku-book/submissions/44451791

前処理でGrundy数を求めておく。

https://atcoder.jp/contests/tessoku-book/submissions/44451943

実験でGrundy数を求めるタイプの問題。
手元で10くらいまでのGrundy数を求めると、
0,0,1,1,2が繰り返し続いていくことがわかる。

https://atcoder.jp/contests/tessoku-book/submissions/44452054

Minimax法的なことをする。
(解説を読んだ感じこれはMinimax法と呼ばれるものではなさそう…?)

https://atcoder.jp/contests/tessoku-book/submissions/44452255

⚠️ **GitHub.com Fallback** ⚠️