赤い星と強い星

ディズニーとかその他の趣味とか

ABC202 D - aab aba baa 別解

ABC202 D - aab aba baaの桁DP+二分探索を用いた解法の解説です.

問題リンク

提出コード

問題概要

 A個のa B個のbからなる長さ A+Bの文字列のうち,辞書順で K番目のものを求めてください.

制約

 1 \leq A,B \leq 30

 A個のa B個のbからなる長さ A+Bの文字列が少なくとも K個は存在することが保証される

解法

a 0b 1に直します.すると,abからなる文字列は2進数とみなすことができます.

この操作をしたあと,元の問題は「 1 B回使われている2進数の小さいほうから K番目の数は何か」と言い換えることができます.

 A+B桁に満たないものは A+B桁になるまで先頭に 0をつけ足せば 0 A個という条件を満たします.また,同じ桁数同士の整数の大小関係はそれを文字列として見たときの辞書順の大小関係と一致します.よって,上の言い換えが成立することがわかります.

次に以下の小問題 f(x)を考えます.

 f(x):=2進法表記された整数 x以下に 1 B回使われている数は K未満かどうか

 f(0)=Trueであって,十分大きな整数 cに対しては f(c)=Falseです.また, x' f(x')=Trueとなるならば 0 \leq y \leq x'を満たす任意の yに対して f(y)=Trueです.同様に, x' f(x')=Falseとなるならば x' \leq yを満たす任意の yに対して f(y)=Falseです.よってこの小問題には単調性があり,ある mが存在して f(m)=True,f(m+1)=Falseとなります.この時の m+1が答えとなります.

小問題の判定について考えてみましょう.「〇〇以下の条件を満たすものの個数」という問題は桁DPというアルゴリズムを用いて求めることができる場合が多く,今回もそれを用いて判定することを考えます.

配列の定義

 dp[i][j][?]:=上から i桁目まで見て, 1の個数が j個で, xより小さいことが確定しているかどうか( ? 0なら xちょうど, 1なら xより小さいことが確定)

遷移

 ?=1からは ?=1にのみ遷移

 ?=0から ?=1に遷移

 ?=0から ?=0に遷移

それぞれの遷移ごとに jの値を増やしたりそのままにしたりして遷移します(詳しくは僕の提出を参考にしてください).

判定内容

 xを2進数表記して,その桁数を nとすると,  dp[n][B][0]+dp[n][B][1] \lt Kかどうか

以上の方法を用いて小問題を構成します.

先に述べたようにこの小問題には単調性があるので,二分探索を用いて答えとなる整数を求めることができます.最後に求めた答えを2進数に変換し, 0aに, 1bに変更した文字列が最終的な答えとなります.

小問題を 1回解くごとに, xの桁数を nとすると O(n ^ 2)であり,二分探索の探索範囲を l,rとすると小問題を \mathbf{log}(r-l)回程度行うので,全体としての計算量は O(n ^ 2 \mathbf{log}(r-l))となり,この問題の条件下では十分高速です.

提出コード

Bonus問題

a A個,b B個からなる文字列 Sが与えられます.a A個,b B個からなる文字列すべてのうち Sは辞書順で何番目か. 10 ^ 9 +7で割ったあまりを求めよ.(要するに元の問題の逆操作です)

 1 \leq A,B \leq 10 ^ 3