ダブリングの基本概念とその応用
ダブリングは、全体の要素数がN個あって1回移動した時にどの要素に到達するのか定まっているとき、「K個先の要素を求めるのに
- 前処理:
O(NlogK) 時間,O(NlogK) 空間 - クエリ:
O(logK)
で行うことができるようにするアルゴリズムです。
繰り返し二乗法もダブリングの一種と捉えることができ、最近共通祖先(LCA)の計算にも利用されます。
アルゴリズム
ダブリングによるK個先の要素の求め方:
- 前処理:「doubling[k][i] :
i 番目の要素から2k 先の要素は何か」を以下の式を利用して計算- doubling[k+1][i] = doubling[k][doubling[k][i]]
- クエリ:前処理した結果を利用して K 個先の要素を求める
- 現在地を now として、
K を2進数として見た時の全ての桁について以下を行うK のk 桁目 が 1 ならば now = doubling[k][now] とする
- 現在地を now として、
※前処理では以下のような計算をします。
- それぞれの要素について 1 個先の要素が何か記録
- 前の結果を利用して、それぞれの要素について 2 個先の要素が何か記録
- 前の結果を利用して、それぞれの要素について 4 個先の要素が何か記録
- 前の結果を利用して、それぞれの要素について 8 個先の要素が何か記録
- 前の結果を利用して、それぞれの要素について 16 個先の要素が何か記録
- …
※クエリでは、前処理した結果を利用しています。繰り返し二乗法について見るとイメージしやすいと思います。
計算量
K個先の要素を求めたい時の計算量は以下のようになります。
- 前処理:
O(NlogK) 時間,O(NlogK) 空間 - クエリ:
O(logK)
問題例: ABC167 D – Teleporter
町が
町 1 から始めた時、最終的にどの町にたどり着くか?
制約
2≤N≤2×105 1≤Ai≤N 1≤K≤1018
考え方
単純にシミュレーションすると、O(K) の計算量になって間に合いません。
そこで、ダブリングの考え方が使えます。
- doubling[k][i] : 町
i から2k 先の町はどこか?
という情報を前計算することで、
- 前処理:
O(NlogK) 時間,O(NlogK) 空間 - クエリ:
O(logK)
計算することができます。
他にも、周期性を利用した解法などもあります。詳しくは D – Teleporter 解説 (AtCoder Beginner Contest 167) を見て下さい。
ディスカッション
コメント一覧
まだ、コメントがありません