ABC113 D - Number of Amidakuji
問題
ABC113 D - Number of Amidakujiです。
解法
方針
まず、求める解を漸化式で表します。 漸化式から解を求めるのはプログラムで地道に計算します。
ざっくりと漸化式を定義する
縦棒の上から cm目のちょっと下に(上からcm目の横棒を移動した後ということ)たどり着くことができる 高さ cm目までの正しいあみだくじの本数を とします。 求める解は です。
初期条件
縦棒1の上端からあみだくじは開始するので、以下が成り立ちます。
また、便宜上、 または を満たす について、 と定義しておきます。
漸化式
縦棒の上から cm目のちょっと下に(上からcm目の横棒を移動した後ということ)たどり着くパターンは以下の3通りです。
- 縦棒の上から cm目のちょっと下(上からcm目の横棒を移動した後ということ)を通過し、 上からcm目の縦棒を繋ぐ横線をたどってくるパターン
- 縦棒の上から cm目のちょっと下(上からcm目の横棒を移動した後ということ)を通過し、そのまま真下にたどってくるパターン
- 縦棒の上から cm目のちょっと下(上からcm目の横棒を移動した後ということ)を通過し、 上からcm目の縦棒を繋ぐ横線をたどってくるパターン
また、上記の各パターンについて、上から cm目の横棒には自由度があることに注意します。 例えば、一つ目のパターンでは、縦棒を繋ぐ横線させあれば、 縦棒を繋ぐ横線があろうがなかろうが構いません (正しいあみだくじとするため、縦棒を繋ぐ横線、および、縦棒を繋ぐ横線は引けないことに注意してください)。 上記のパターン分けと自由度から以下の形の漸化式を得ます。
は自由度を表す係数です。 縦棒から縦棒までの間に(正しいあみだくじであるように)横線を引くパターン数をで表しています。 ただし、 ならば とします。
あとは、を解析すれば、を計算できます。
を解析する
ならば としているので、いったん、 j < j' として議論します。
まず、縦棒 の間には横線を引けるスペースが個あります。 スペースの数だけに依存するので、 で表せます(スペースの数が個のときの横線を引くパターン数を で表してます)。
まず、連続したスペースに横線を引けない制約から、 は直ちにわかります。 さらに、最も左のスペースに横線を引く場合、その右のスペースに横線は引けないので、 という漸化式を得ます。 すなわち、(初期条件は少し異なりますが) はフィボナッチ数列です。
さらに、 ならば なので、 と定義しておくと計算の都合がよいです。
以上より、 は上記フィボナッチlikeな値 で求められることがわかりました。
求める解のまとめ
以下の漸化式について、 が求める解です。
ただし、
です。 また、解を出力する際は1000000007の剰余をとることを忘れないように注意してください。
ACしたコード
from functools import lru_cache H, W, K = map(int, input().split()) def f(k): return 1 if k <= 0 else f(k-1) + f(k-2) @lru_cache(maxsize=H*W) def a(i, j): if j < 1 or j > W or (i == 0 and j != 1): return 0 if i == 0 and j == 1: return 1 return (f(j-3) * f(W-j-1) * a(i-1, j-1) + f(j-2) * f(W - j - 1) * a(i - 1, j) + f(j - 2) * f(W - j - 2) * a(i - 1, j + 1)) % 1000000007 ans = a(H, K) print(ans)