競プロ備忘録

競プロerの備忘録

ABC66D - 11

こういうO(1)で気合導出、みたいな問題はめちゃくちゃ苦手…

解法

早い話、ありうる部分列を列挙して重複を除去すれば答えが出る。制約が大きいので重複の仕方が爆発してダメそうに見えるが、重複している数字が1個しかないので、重複の仕方を上手く見つけて場合分けすれば計算できる。

重複している数字を Tと置いて Tで数列 Aを区切り、それぞれ左から区間 (L, T, M, T, R)とする。

それぞれの区間から1個も使わないときと1個以上使うときを 0, 1に対応させると、

 00010 - 01000 = (T)
 00011 - 01001 = (T, R)
 10010 - 11000 = (L, T)
 10011 - 11001 = (L, T, R)

の4つの組が重複していることに気づける。

なので、それぞれの Kに対して \binom {N+1} {K}から以上4つの場合の数を引けば答えが出る。

 (T)については、 K = 1のときにだけ 1を引けばよい。

 (T, R), (L, T)については、 L, Rからそれぞれ K-1個を選ぶ数(1個は Tのために予約している)なので、それぞれ \binom {length(R)} {K-1}, \binom {length(L)} {K-1}となる。

 (L, T, R)については、 L, R双方から最低でも1個ずつ選んだうえで合計 K-1個選ぶ数なので、 \binom {length(L) + length(R)} {K-1}から、 L, R片方からだけ K-1個選んでしまう数を引けばよく、結局、 \binom {length(L) + length(R)} {K-1} - \binom {length(L)} {K-1} - \binom {length(R)} {K-1}となる。

以上から、 K-1のときは、 \binom {N+1}{K} - 1、それ以外のときは \binom {N+1}{K} - \binom {length(L) + length(R)} {K-1}が答えとなる。

時間計算量については、二項係数が階乗、逆元の階乗の前計算によって O(1)で求まるので、全体として O(N)となる。

実装例は以下。

Submission #39932727 - AtCoder Beginner Contest 066