0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

教育的なdp問題【競技プログラミング】

Last updated at Posted at 2024-09-16

はじめに

  • 典型的なdp問題を解いて、dpの感覚を掴もうと思う。

問題

  • 典型90問の008からです。
  • ある文字列Sから、順番を保ったまま7文字を抜き出して、T = "atcoder"を作る方法は何通りあるか?
    • 例は以下のとおり。
    • S = "atcoder" からは、1とおり。
    • S = "atcodre" からは、0とおり。
    • S = "atcoderatcoder" からは、8とおり。
    • S = "aattccooddeerr" からは、128とおり。$(=2^7)$

dpの方針

  • 基本形は、dp[i][??] (??は何かの状態を表す指標)になる。
  • 今回においては、iは当然、文字列Sの何文字目まで進んだかを意味して、dp[N][??]が最終的な答えになるようなイメージかな。
  • 具体的に考えれば、dp[i][j](i in 0..<N , j in 0..<7)として、これを、Sの「i-1」文字目まで取捨選択終わった時点で、Tの「j-1」文字目までを選択し終えているときの、場合の数とする。
  • つまり、dp[i][j]の数値が算出済みである状態で、S[i]、T[j]の文字に着目している場面、と言うこと。
  • この方針に沿ってコードを書くと以下のとおり。
extension Array {
    init(_ cnt: Int, _ v: Element) {
        self = [Element](repeating: v, count: cnt)
    }
    init<T>(_ cnt2:Int, _ cnt1:Int, _ v:T) where Element == [T] {
        self = [[T]](cnt2,[T](cnt1,v))
    }
}

// dp準備
var dp = [[Int]](N+1,T.count+1,0) // 省略記法でのイニシャライザ。要素数 N+1 がキモだね。

// 初期化
dp[0][0] = 1

// 遷移
for i in 0..<N {
    for j in 0...T.count{

        // Sの文字列を進むとき、Tの文字列T[j]をS[i]から選ばない決定をした場合の遷移
        dp[i+1][j] += dp[i][j] // iのみ遷移

        // Sの文字列を進むとき、Tの文字列を選ぶときの遷移
        if j<T.count && S[i] == T[j] {
            dp[i+1][j+1] += dp[i][j] // iもjも遷移
        }
    }
}
  • 上記dpを使った本問の答えは、当然dp[N][7]となる。
  • 本問の制約は、$N≦10^5$だから、上記の計算量O(7・N)だと余裕です。30ms未満でACでした。

おわりに

  • まだ、この手の問題で、解法がパッと思いつかない。dpについては、数をこなすしかないのかな。
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?