ABC113 D - Number of Amidakuji (400点)

Change log
9sako6
9sako6
9sako6
9sako6
9sako6

優秀なフレンズの助言をもらいながらACできたので、忘れないうちに記事にします。

#問題

概要(適当なのでちゃんと公式の問題文を読んでね)
縦棒の長さHHと本数WWが与えられる。縦棒の間に好きに横線を引いて、あみだくじを作る。11番目の棒の上端から, 横線があれば必ずそれを通るというルールで下へたどったときに、最終的にたどり着く縦棒の番号がKKとなるような「正しいあみだくじ」の本数を10000000071000000007で割った余りを求めなさい。
制約
1H1001 \leq H \leq 100
1W81 \leq W \leq 8
1KW1 \leq K \leq W

#考察

考えの流れ

  • ある高さにおける横線の引き方は高々2(81)2^{(8-1)}通り
  • ある高さhhww本目に至るのが何通りかわかっていたらh+1h+1についても計算できるんじゃないか
    • 各高さについて分割して考えられそう
  • ある高さhhww本目に至る状態をまとめて扱えそう
  • DPかな
  • 計算量を見積もる。ある高さにおいて、全ての横線の引き方である2(81)2^{(8-1)}通りの状態を考え、それぞれがあみだくじの要件を満たしているかを計WW本について調べる。これを全ての高さ(100\leq 100)について行うので、O(27×8×100=210×100105)O(2^7 \times 8 \times 100 = 2^{10} \times 100 \simeq 10^5)で間に合いそう

上記のような考察でDPっぽいことがわかったので、状態と遷移を考えます。 dp[h][w]dp[h][w]を、高さhhww番目(0-indexed)に至るのに何通りあるか、と定めます。

遷移を考えます。 今、高さhhww番目の横線にいるとします。ここに至るまでにdp[h][w]dp[h][w]通り存在します。

abc113_d_1

w+1w+1に向かう横線があれば、w+1w+1番目の横線に移動して次の高さに進みます。dp[h+1][w+1]+=dp[h][w]dp[h+1][w+1] += dp[h][w]

abc113_d_2

w1w-1に向かう横線があれば、w1w-1番目の横線に移動して次の高さに進みます。dp[h+1][w1]+=dp[h][w]dp[h+1][w-1] += dp[h][w]

abc113_d_3

両隣に横線がなかったら、同じww番目のまま次の高さに進みます。 dp[h+1][w]+=dp[h][w]dp[h+1][w] += dp[h][w]

abc113_d_4

ちなみに、両隣に横線があることはありません。正しくないあみだくじだからです。そのような正しくないあみだくじは予め弾いておきます。

初期条件はdp[0][0]=1dp[0][0]=1です。高さ00、すなわち、まだどの高さにも移動してないとき、00番目の横棒にいるのは11通りだからです。

H, W, K = gets.split.map(&:to_i)
MOD = 10 ** 9 + 7
dp = Array.new(H + 1) { Array.new(W, 0) }
dp[0][0] = 1
H.times do |h|
  # ある高さにおいて、2^(W-1)通りの横線の引き方がある
  (0...(1 << (W - 1))).each do |bit|
    # check
    # 正しくないあみだくじを弾く
    # 1が連続して2つあったらアウト
    flag = false
    (1...W).each do |i|
      if bit[i] == 1 && bit[i - 1] == 1
        flag = true
      end
    end
    next if flag
    # transition
    # 横線をそれぞれ調べて遷移
    W.times do |w|
      if w != W - 1 && bit[w] == 1
        target = w + 1
      elsif w != 0 && bit[w - 1] == 1
        target = w - 1
      else
        target = w
      end
      dp[h + 1][target] = (dp[h + 1][target] + dp[h][w]) % MOD
    end
  end
end
puts dp[H][K - 1]

submission

#学び

DPを使うところまで漕ぎ着ければ、DPに慣れてる人なら解けそう。 DPに至る思考として

  • 分割して解けないか
  • まとめて扱えないか

みたいなのがありそう。

DPの状態と遷移自体はシンプルなので教育的なDP問題だと思う。