AtCoder ARC 036 C – 偶然ジェネレータ

競技プログラミング解説記事

問題概要

0, 1, ? からなる \(N\) 文字の文字列が与えられる。? に 0 か 1 を記入して、「どの連続部分列も、0と1の個数差が \(K\) 以下になる」という条件を満たす方法は何通りあるか?

制約

\(1 \le K \le N \le 300\)

解答

1. まずは判定問題

数え上げの問題では、まず判定問題を考えることで方針が浮かぶ可能性がある。今回では「個数差が最大になる連続部分列について、その個数差はいくつか?」という問題を考える。

まず0を−1にして考える。連続部分列に関する問題なので、初項からの合計を考える。この時、最大の個数差は、「合計値のうち最大のものから最小のものを引いたもの」になる(図1)。

図1 判定問題
2. DP

「合計値のうち最大値 – 最小値が \(K\) 以下になる」という条件は扱いにくいため、最小値を固定(ここでは \(L\) とする)して、「合計値が \(L\) 以上 \(L + K\) 以下になる」という条件に変換して考える。これは単純なDP(DP[i][j] := i 文字目まで見て、合計値が j となる場合の数)を適用し、\( L \le j \le L + K\) の範囲外には遷移しないことで求めることができる。

しかしこれでは、重複が発生してしまう。重複を取り除くために、ここでは「最小値(=L)を達成した瞬間があるか?」をDPの引数として持たせることで、重複をなくすことができる。

コード

コメント