問題
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)