Official

F - Inserting Process Editorial by toam


操作を逆から見て,\(T\) から一文字ずつ削除していくことで 空文字列にする方法を数えることにします.

残った文字の位置を集合で持つことにします.今残っている位置が \(S=\lbrace S_1,S_2,\ldots,S_k\rbrace\ (1\leq S_1\lt S_2\lt \ldots\lt S_k\leq N)\) だったとします.文字列から文字を削除することは,ある \(i\) を選んで \(S\) から \(S_i\) を削除することに対応します.

ただし,削除した結果同じ文字列になってしまうことがあります.例えば,\(T\)abcade\(S=\lbrace 1, 4, 6\rbrace\) のとき,\(S\) から \(1\) を削除しても \(4\) を削除しても残った文字列は ae となってしまいます.この重複を避けるためには,例えば以下のように制限すればよいです.

  • \(i\geq 2\) かつ \(T_{S_{i-1}}=T_{S_{i}}\) のとき,\(S\) から \(S_i\) (右側)を削除していけない.(すなわち,同じ文字が連続して残っている区間では左から順に削除する.)

このような遷移の制限のもと,bit DP でこの問題を解くことができます.計算量は \(O(N2^N)\) です.

mod = 998244353

n = int(input())
t = input()
dp = [0] * (1 << n)
dp[(1 << n) - 1] = 1
for bit in range((1 << n) - 1, -1, -1):
    dp[bit] %= mod
    pre = "?"
    for i in range(n):
        if (bit >> i) & 1:
            if pre != t[i]:
                dp[bit ^ (1 << i)] += dp[bit]
            pre = t[i]

print(dp[0])

posted:
last update: