geam1113’s diary

主にAtcoderのコンテストの備忘録を書きます。AtCoder緑と水色を行ったり来たりしています。

ARC133 参加記録

コンテスト中AC:A,B

A - Erase by Value

同じ数は消えるので、一旦連続して重複した数について、重複を削除して考えます。
A_1から始めて、単調増加している間は、消すと辞書順では大きくなってしまうので、消さない方がよいです。
そこで、減少に転じた時に、その直前の数(すなわち、A_1を開始点とした、単調増加な部分の最大値)を消してみます。この時消す数をA_kとし、生成される数列をBとします。

すると、A_kより後の数を消すと、必ずA_1,\cdots A_kという部分が残るので、この時生成される数列がBより辞書順で小さくなることはあり得ません。よって、Bが辞書順最小となります。

なお、減少に転じない場合もあるので、その場合は末尾の数を削除対象にします。
[提出コード] (https://atcoder.jp/contests/arc133/submissions/28684574)

B - Dividing Subsequence

P_i,Q_jを、それぞれa_k,b_kとすることをP_iQ_jを対応させると呼ぶことにします。
また、問題文の制約に沿って生成されるa,b適合列と呼ぶことにします。適合列の要素数と言った時にはa (またはb)の要素数を指すことにします。

P_iQ_jを対応させた時に得られる適合列の要素数の最大値は、

  • \{P_1,P_2,\cdots ,P_{i-1}\}と\{Q_1,Q_2,\cdots ,Q_{j-1}\}から作られる適合列の内、要素数が最大であるもの + 1

です。

添字に着目すると、i' \lt iかつj'\lt jを満たすすべてのi',j'の適合列の要素数の最大値が計算されていれば、i,jのときの最大値を計算できます。そこで、添字の問題に帰着させます。  

P_iQ_jが対応可能である場合にA_k=i,B_k=jとなる配列A,Bを作ることを考えます。

PQのあり得るすべての組をA,Bに記録します。
例)P=\{3,1,4,2\}, Q=\{4,2,1,3\}
P_1Q_4と対応可能
P_2Q_1,Q_2,Q_3,Q_4と対応可能
P_3Q_1と対応可能
P_4Q_1,Q_2と対応可能
A=\{1,2,2,2,2,3,4,4\}
B=\{4,1,2,3,4,1,1,2\}

A,Bの構築方法は後述します。一見全組を得るのにO(N^2)になりそうですが、エラトステネスの篩と同じ様にO(NlogN)で構成できます。

B_iをキーとして昇順ソートします。すると、j \lt iならB_j \leq B_iになります。
一旦、B_j=B_iの場合を無視すると、

  • j \lt iを満たすj (つまり、iより前に出現したもの)のうち、A_j \lt A_iとなるA_jから最大値を得る

問題となります。これはBynary Indexed Treeによって反転数を求める問題の考え方を応用できます。
今回は最大値を得たいので、maxの二項演算が規定されたSegment Treeを使います。Segment Treeの値を保持する配列をdpとします。最初、全て0です。

dp[A_i]を計算したいとき、max(dp[0],dp[1],\cdots ,dp[A_i - 1])という計算によって、A_j \lt A_iとなるA_jから最大値を得ることができます。
そして、
dp[A_i]\leftarrow max(dp[0],dp[1],\cdots ,dp[A_i - 1])+1
と更新すれば良いです。B_j = B_iの場合ですが、今回はこれを満たすA_jは無視したいです。そこで、B_iが等しいものについて最大値を全て計算し終わった時点で、一括して上記の更新を行うようにすれば良いです。

上に示した方法によって、iの小さい方から順に最大値を計算して行くことができます。

さて、後回しにしていた数列A,Bの構築方法です。
配列Eを用意し、Q_iが出現したインデックスiを記録します(E[Q_i] = i)。
例)
Q = \{4,1,5,7,2,3,6\}の時、E = \{2,5,6,1,3,7,4\}

P_iと対応可能なQ_jP_iの倍数です。よって、この時のjを得たい場合、配列Eを利用すると、
j = E[P_i],E[2P_i],E[3P_i],\cdots
というように得ることができます。

これはエラトステネスの篩と似たような処理であり、O(NlogN)です。よって、A,Bそれぞれの配列サイズもNlogNで収まると言えます。

全体の計算量は、Eの構築にO(NlogN)で、最大値の計算と更新にもO(NlogN)となるので、O(NlogN)だと思います。
提出コード

ちなみに、上記コードはインデックスの組を二次元配列として持たせています。
iと組が作れるjは、B[i] = j_1,j_2,...