Strivore - abc 171 f

#二項係数


まず, 愚直な dp を考える.

rep(i, sz) rep(j, sz(s) + 1) rep(l, 26) {
  if (s[j] - 'a' == l) add(dp[i + 1][j + 1], dp[i][j]);
  else add(dp[i + 1][j], dp[i][j]);
}
cout << dp[sz][sz(s)] << endl;


rep(l, 26) をなくすと以下のようになる.

rep(i, sz) rep(j, sz + 1) {
  add(dp[i + 1][j + 1], dp[i][j]);
  add(dp[i + 1][j], 25LL * dp[i][j] % mod);
}
ll ans = 0;
rep3(i, sz(s), sz + 1) add(ans, dp[sz][i]);
cout << ans << endl;


sample 1 で dp の違いを確かめる.

1 0 0 0 0
25 1 0 0 0
625 50 1 0 0
15625 1875 75 1 0
390625 62500 3750 101 0
9765625 1953125 156250 6376 0
244140625 58593750 5859375 322026 0
103515583 708984368 205078125 14232051 0
587889561 828124664 835937458 575111451 0
1 0 0 0 0 0 0 0 0 0
25 1 0 0 0 0 0 0 0 0
625 50 1 0 0 0 0 0 0 0
15625 1875 75 1 0 0 0 0 0 0
390625 62500 3750 100 1 0 0 0 0 0
9765625 1953125 156250 6250 125 1 0 0 0 0
244140625 58593750 5859375 312500 9375 150 1 0 0 0
103515583 708984368 205078125 13671875 546875 13125 175 1 0 0
587889561 828124664 835937458 546875000 27343750 875000 17500 200 1 0


5 行目で, 100 1 か 101 か違いが出始める.
下のコードでは, すべて *1 の遷移と *25 の遷移があるのに対し, 上のコードでは, j = sz(s) のとき, *26 の遷移をする.
よって, 下のコードでは, dp[sz] の sz(s) ~ sz までを足す.


手書きで遷移を書いてみると, 二項係数が見えてくる.
よって, dp[sz] の「sz(s) ~ sz までを足す」分の計算量でいい.
f:id:tac_12:20200623234317p:plain:w300


ソースコード
https://atcoder.jp/contests/abc171/submissions/14641134


類題
https://tac-12.hatenablog.com/entry/2020/05/11/154759