[yukicoder] No.2166 Paint and Fill

スポンサーリンク

概要

問題文 →
公式解説 →
自分の提出 →

制約 1 の取り扱いが、少し別解っぽかったので書いておきます。

公式解説補足

[x0]f=1 となる(疎な)多項式と定数 N に対して、Fk=[xk]f(x)N で定まる数列 {Fk} は p-recursive になります。

F=fN とすると、対数微分 FF=Nff から分かる式 fF=NfF から F の係数の間の関係式が得られるためです。したがって、本問の解はテストケースごとに O(K) 時間で計算できます。

関連:https://judge.yosupo.jp/problem/pow_of_formal_power_series_sparse

これをさらに高速化することが求められています。

解法(制約 1)

クエリ総数を Q、クエリを表す文字は (n,k)として、k の最大値を K と書きます。

上述の係数間の漸化式を行列で書き表すことで、次に帰着できます:

0j<K に対して、1 次多項式を成分とする (2,2) 行列 Fj(x) が与えられる。
(n,k) に対して次を求めるクエリに Q 回答えよ:Fk1(n)F0(n)(10).

適当なバケットサイズ B を設定して、各 i に対して次を行うことで解きます。

  1. 区間積 j[Bi,Bi+B)Fj(x) を計算する。ただし積は j について降順。計算結果は B 次多項式を成分とする (2,2) 行列。
  2. 区間積 j[0,Bi)Fj(x) を計算する。(やはり j について降順)
  3. k[Bi,Bi+B) を満たすクエリ (n,k) に対して、2. の区間積を x=n で評価したもの j[0,Bi)Fj(n) を計算する。
  4. k[Bi,Bi+B) を満たすクエリ (n,k) に対して答を計算する。

それぞれの方法と計算量を確認します。

  1. 1 次式 B 個の総積で、分割統治と畳み込みを利用して O(Blog2B) 時間でできることがよく知られていると思います(関連:https://judge.yosupo.jp/problem/product_of_polynomial_sequence)。すべての i にわたる計算量の合計は O(Klog2B) 時間です。
  2. は、1. の結果を順番に畳み込むことで行います。畳み込みが O(KlogK) 時間、これを O(K/B) 回行うため、i にわたる和は O(K2logK/B) 時間です。
  3. は、2. の結果を成分ごとに多点評価することで得られます。バケット内のクエリの個数を Qi として、O(KlogK+Qilog2Qi) 時間。バケットに関する総和は O(K2logK/B+Qlog2Q) 時間です。なお、以下に述べるように、最終的にはこの行列に (10) をかけたものだけが必要なので、多点評価を行う成分は 2 つだけでよいです。
  4. は、3. で計算した (j[0,Bi)Fj(n))(10) に対してさらに j=Bi,,k1 の順に左から行列 Fj(n) をかけることで行います。行列行列積ではなく行列ベクトル積を反復する方が定数倍がよいです。バケット内のクエリの個数を Qi として、O(QiB) 時間。バケットに関する総和は O(QB) 時間です。

X=max(K,Q) として、計算量に現れた項を見ていくと、全体の計算量は O(X2logX/B+Xlog2X+XB) と書けることが分かります。B=XlogX とすることで、全体の計算量は O(X1.5logX) となります。実装の定数倍を減らしバケットサイズを調整することで、この方針で AC することができます。

X2logX/B の定数倍が重く、XB の定数倍が軽いからか、BXlogX よりもかなり大きくとった方が実行時間が短くなりました。

タイトルとURLをコピーしました