CF 822 E - Liar
問題
問題概要
長さの文字列と長さの文字列が与えられる。をいくつかの部分文字列に分解して、その中から任意の個数を選んで順序を崩さないように結合させる。その結合させた文字列をと一致させるために、できるだけ結合の数減らしたい。個以下の文字列で実現できるかを判定せよ。
- はアルファベット小文字
アイデア
計算量をとりあえず気にしないのであれば、とりあえずdp[i][j] = sのi文字目まで使った、tのj文字目まで使った状況での分割回数のmin
を持つとdp[n][m]<=xかどうかで判定ができるが、明らかに間に合わない。
ここで、分割回数の上限が小さいことに着目すると、次のようなdpも考えられる:dp[i][j] := sのi文字目まで使った、既に連結した文字列がj個の時、tの何文字目までを作れるかのmax
。このようにすると状態数はになる。そして、遷移がどうなるのかというのを考えると、1,2,3, ... 文字を採用するというのを全部試すというのは結局ムリだが、i文字目からスタートする部分文字列を採用する時場合は、最適なのは取れる限りまで取る(中途半端に切るのは無駄)ということしか考える必要がないので、各状態において遷移は「i文字目からスタートするものを採用する/しない」の2つしかいらないことになる。
sのi文字目からと、tのdp[i][j]文字目からのLCPはSuffixArrayにsとtを結合させたものを入れておいて、RMQを使うことで高速に処理することが出来るので、DPの遷移はになる。
実装(C++)
続きを読むCF 940 F - Machine Learning
問題
問題概要
長さの数列がある。次のようなクエリを考える:
- クエリ 1 : 区間について、数字が現れる回数をとして、集合のmexを答える。
- クエリ 2 : の値をに変更する。
以上のクエリが合計で個与えられるので、順に処理せよ。
アイデア
愚直な処理はTLEしてしまう(submission)。
まず、クエリ1で出力すべき値がそこまで大きくない。なぜなら、xを答えにさせるには、最低限の現れる回数をを考えると回現れる数字がそれぞれあるということなにで、答えはで抑えられている。
そこで、もし変更がなければMoが出来るなーと思いが巡った(その数字が現れる回数を配列に、現れる回数の個数を配列で管理することにすると、区間を1伸ばしたり縮めたりするのはで出来、クエリに対しては上の考察からで答えられる)。
今回は、2種類のクエリが来ると考えるのではなく、クエリ1しか来ないと考えて、クエリ1を次のように3つの数で与えられるクエリということにする:
- クエリ : 既にクエリ2を個実行した状態で、区間について、数字の出現頻度のmexを答える。
クエリをこの形に言い換えると、状態としてこの3変数を持ち、いずれかの変数を+1,-1したときにがどうなるかの更新はで行うことが可能である。この事実を踏まえて、とに関してはブロックサイズごとに組にして分けることにする。このとき、クエリ毎にはだけ変化するので、全体として、は回だけの変化するので、全体としての変化をする。とのオーダーが等しいことも考慮すると、ブロックサイズとして適切なのはであり、このとき全体はとなる。
あとは、Moをする時の頻度のカウントにmapなどを使うと計算量が悪くなってしまうので、予め登場する数字をチェックして座圧しとくと良い。