fuu32のブログ

精進記録

Codeforces Round #523 C - Multiplicity

問題概要

Problem - C - Codeforces

数列aが与えられ、数列aから0個以上の要素を取り除いた数列を数列bという。
数列bの要素が1つ以上あり各b_ii  ( 1 \leq i \leq |b| ) で割り切れる時、数列bを数列aの良い部分列と呼ぶ。
数列aの良い部分列の総数を109+7で割った余りを求める。

制約

1 \leq N \leq105
1 \leq a_i \leq106

考えたこと

解説ACをしたのでこれCodeforces Round #523 Editorial - Codeforcesと同じことをしました。

まず、「 dp[ i ][ j ] :=  a_iまで見たときにj個で構成される良い部分列の数」というDPを考える。 遷移は以下のようになり、 \sum_{i=1}^n dp[ n ][ i ] が答えになるが制約的に二次元配列ではもてない。

{} $$ dp[ i ][ j ]= \left\{ \begin{array}{} dp[ i-1 ][ j ] + dp[ i-1 ][ j-1 ] & ( a_i が j で割り切れる時) \\ dp[ i-1 ][ j ] & (上以外の時) \end{array} \right. $$

Editorialには dp[i] dp[i-1]にのみ依存するから1次元でもうまくいくよ!みたいに書いてあったがこれでは納得ができなかった。
参加者のコメントを参考に考えた結果、 「 dp[ i ]:= i個で構成される良い部分列の数」というDPを考えるとする。 例えばa_i=6の時、6の約数は{1,2,3,6}なのでa_iは数列bの1番目、2番目、3番目、6番目に置くことができるのはわかる。 なのでa_iの約数x_iを降順に dp[x_j]+=dp[x_j-1]のように更新していけばいいことになる。 昇順に更新していった場合、a_i=6の例で言えば1番目にa_iを使ったのに2番目でもa_iを使うといったことが起きてしまうため正しくないことがわかる。

i=1からi=Nまでのa_iに対して順に上の操作を行い、適宜109+7でmodをとれば\sum_{i=1}^n dp[i]が答えになる。
提出コード:Submission #46102628 - Codeforces