ABC234F - Reordering

考え方

こうやって遷移できるんですね.なるほどぉ〜.

長さ$j$の文字列を作るとき,新しい文字を$k$個使うとすると,

  • 新しい文字($i+1$番目の文字)を入れる場所を,$j$個の候補から$k$個選べば,
  • あとは,$i$種類の文字で長さ$j-k$の文字列をつくる方法の数になる
ということですね.

回答例

二項係数を予め(効率的に)計算しておかないとTLEします.

from collections import defaultdict

S = input()
N = len(S)
mod = 998244353

fact = [1] * (N + 1)
for i in range(N):
  fact[i + 1] = (i + 1) * fact[i]
  fact[i + 1] %= mod
  
fact_inv = [1] * (N + 1)
fact_inv[N] = pow(fact[N], mod - 2, mod)
for i in range(N - 1, -1, -1):
  fact_inv[i] = (i + 1) * fact_inv[i + 1]
  fact_inv[i] %= mod
  
ncr = [[1] * (N + 1) for _ in range(N + 1)]
for i in range(N + 1):
  for j in range(i + 1):
    ncr[i][j] = fact[i] * fact_inv[j]
    ncr[i][j] %= mod
    ncr[i][j] *= fact_inv[i - j]
    ncr[i][j] %= mod

cnt = defaultdict(int)
for s in S:
  cnt[s] += 1
  
dp = [[0] * (N + 1) for _ in range(26 + 1)]
dp[0][0] = 1
for i in range(26):
  for j in range(N + 1):
    for k in range(min(j, cnt[chr(ord('a') + i)]) + 1):
      dp[i + 1][j] += ncr[j][k] * dp[i][j - k]
      dp[i + 1][j] %= mod
    
ans = -1
for i in range(N + 1):
  ans += dp[26][i]
  ans %= mod
print(ans)

【参考】Submission #28399481 - AtCoder Beginner Contest 234