多項式を使うテクニックたち
Latest Author 37zigen /Date 2021-08-07 05:46:36 / Views 16483注意:yukicoderやその他のサイトの問題に対するネタバレがある可能性があります
以下では多項式は可換環である$R$を係数とするとする。 計算量は$R$上の基本演算が定数時間でできるとして考える。ただしあまり厳密ではない。 競技プログラミングにおいてはたいていワードサイズのmodを取るので定数時間で計算できるとして問題ない事が多い。
多項式同士の乗算の計算量を$M(n)$とする。多項式除算も$O(M(n))$で計算できる。 単純なアルゴリズムでは$M(n) \in O(n^2)$だが、$R = {\mathbb Z}/m{\mathbb Z}$の場合はFFTを用いることで$M(n) \in O(n \log n \log \log n)$にできる。
多項式の総和
$p$を$k$次の多項式とするとき、$P(n) = \sum_{i=0}^{n-1} p(i)$は$k+1$次以下の多項式となる。 $\sum_{i=0}^{n-1} i = \frac{n(n-1)}{2}$などの公式として有名だろう。
多項式のある種の逆元
有名なpower seriesの式$\sum_{i=0}^{\infty} a^i = \frac{1}{1-a}$は多項式にも適用できる。 つまり、多項式$f = \sum_{i=0}^k a_i X^i$に対し、ある種の逆元を$\sum_{i=0}^{\infty} (1-f)^i$と表すことができる。 この式は$a_0 = 1$である場合に限りよく定義でき、これは多項式環の拡張である"formal power series"環上に値を取る。
$f$に$a_0^{-1}$かけることで、つまり$f^{-1} = a_0^{-1} \sum_{i=0}^{\infty} (1 - a_0^{-1} f)^i$として、$a_0 \in R^*$である限りこれを求めることができる。
多項式の平行移動
$f(X):=\sum_{i=0}^N a_iX^i$を$C$だけ平行移動した$f(X+C)$の係数を$O(N\log{N})$で求める。二項展開して地道に計算することで \begin{align} f(X+C)=&\sum_{i=0}^N a_i (X+C)^i \\ =&\sum_{i=0}^N a_i \sum_{j=0}^i \binom{i}{j}X^jC^{i-j}\\ =&\sum_{i=0}^N X^i \sum_{j=i}^N a_j \binom{j}{i} C^{j-i}\\ =&\sum_{i=0}^N \frac{X^i}{i!} \sum_{j=i}^N a_j \frac{j!}{(j-i)!} C^{j-i}\\ =&\sum_{i=0}^N \frac{X^i}{i!} \sum_{k=0}^{N-i} a_{k+i}(k+i)! \frac{C^{k}}{k!} \\ =&\sum_{i=0}^N \frac{X^i}{i!} [s^{-i}] g(s)\exp(Cs) \\ \end{align} を得る。ただし$g(s):=\sum_{i=0}^N a_i i! s^{-i},\exp(Cs):=\sum_{i=0}^N \frac{(Cs)^{i}}{i!}$とする。$g(s)$と$\exp(Cs)$の畳み込みになっているのでFFTで$O(N\log{N})$で計算できる。 これは平行移動後の関数をラプラス変換したものの逆ラプラス変換$\Theta(X+C) \sum_{k=0}^N f_k (X+C)^k = \mathcal{L}^{-1}[\exp(Cs)\sum_{k=0}^N a_k\frac{k!}{s^{k+1}}]$を計算しているとみなせる(?)。$\Pi_{i=1}^{N} (1+X^{s_i})$
分割数を計算するときに$\Pi_{i=1}^{N} (1+X^{s_i})$を計算したくなることがある。 https://arxiv.org/abs/1807.11597にて $A(X):=\Pi_{i=1}^{N} (1+X^{s_i}) \bmod X^{t+1}$を$O(t\log t)$で求めるアルゴリズムが示されている。 $\log(1+X)=\sum_{i=1}^\infty \frac{(-1)^{i-1}}{i}X^i$であるから \begin{align} \log\Pi_{i=1}^{N} (1+X^{s_i})=&\sum_{i=1}^N\log(1+X^{s_i}) \bmod X^{t+1}\\ =&\sum_{i=1}^N\sum_{j=1}^\infty \frac{(-1)^{j-1}}{j}X^{js_i} \bmod X^{t+1}\\ =&\sum_{i=1}^t \sum_{j=1}^{[t/j]} a_i\frac{(-1)^{j-1}}{j}X^{j i} \bmod X^{t+1} \end{align} ただし、$a_i:=\#\{j:s_j=i\}$とする。$O(\sum_{j=1}^{t}[t/j])=O(t\log t)$で計算できる。あとは$A(X)=\exp(\log(A(X))$から計算すればよい。演習問題
- AGC041-D (Ryuhei_Moriさんの解説)
- EDPC-M (maspyさんの解説)
母関数
数列に対し、有理関数が母関数であることと線形漸化式であることは同値である。
・線形漸化式⇒母関数は有理関数
数列$\{a_{n}\}_{n \geq 0}$が$n \geq M$のとき漸化式$a_{n}=\sum_{k=1}^{m}α_{k}a_{n−k}$ で表されているとする。(ただし$α_{k}$は定数かつ$\alpha_m \neq 0$)
このとき母関数を$f$として $h(x):=1-\sum_{k=1}^{m}α_{k}x^{k} , g:=hf$とする。
$g$の各次数の係数について考えれば、$M$次以上は全て相殺されるので$g$は高々$M-1$次多項式。
$h$は定義より明らかに$m$次多項式なので$f=g/h$は有理関数。
・母関数が有理関数⇒線形漸化式
有理関数$f$を母関数とする数列$\{a_{n}\}_{n \geq 0}$を考える。
$f$は有理関数なので多項式$g,h$により$f=g/h$と表せる。
$hf=g$の両辺を$n(>\max\{\deg~g,\deg~h\})$回微分するとライプニッツ則により
$\sum_{k=0}^{\deg~h}\binom nk f^{(n-k)}(x)h^{(k)}(x)=0$ ($\binom nk$は二項係数)
となるので$x=0$を代入し、$k=0$の項を残して移項すると
$f^{(n)}(0)h(0)=-\sum_{k=1}^{\deg~h}\binom nk f^{(n-k)}(0)h^{(k)}(0)$
両辺を$h(0)n!$で割り、$f$のマクローリン展開により$a_{n}=f^{(n)}(0)/n!$であることを用いると
$a_{n}=-\sum_{k=1}^{\deg~h}h^{(k)}(0)/h(0)/k!*a_{n-k}$
ここで$h^{(k)}(0)/h(0)/k!$は$n$に依らない定数であるから、これは$(\deg~h)+1$項間線形漸化式である
多項式で表せるDP
以下の問題を考える: 「正整数の列$a$が与えられるとき、$a$の重複なし部分和でちょうど$b$になるものは何通りあるか?」 この問題は典型的なDPであるが、以下のように多項式によって表せる: 「$f = \prod_i (1+X^{a_i})$とするとき、$f$の$b$次の係数を求めよ」 この多項式はこの問題に関する母関数であるとも考えられる。
また、同じように、「正整数の列$a$が与えられるとき、$a$の重複あり部分和でちょうど$b$になるものは何通りあるか?」という問題の場合、 $f = \prod_i \sum_{j=0}^{\infty} X^{j a_i}$となるが、逆元を用いて$f = \prod_i (1-X^{a_i})^{-1}$とも表せる。
多次元のDPであっても多変数多項式によって表せ、同じように考えられる。
"戻すDP"
典型的な部分和数え上げ問題のDPの遷移が多項式の掛け算として表せることがわかった。 ならば、その逆演算である割り算がどう適用できるかを考えてみるのは自然だろう。
たとえば、$f = \prod_i (1+X^{a_i})$である場合、$(1+X^{a_i})$で割ることでDPを"戻す"ことができる。 つまり、$a$から要素$a_i$を削除した列でのDP結果が得られる。 実際には、$(1+X^{a_i})^{-1} = \sum_{j=0}^{\infty} (-X)^{a_i j}$となる。 単純に再計算する場合$O(nb)$程度の計算量がかかるが、この場合重複あり部分和DPと同じように実装することで$O(b)$の計算量で求めることができる。
重複ありの場合、$f = \prod_i (1-X^{a_i})^{-1}$であるが、 $((1-X^{a_i})^{-1})^{-1} = 1-X^{a_i}$というようにそれ自身であるので、"戻す"場合は重複なしDPのような掛け算によって実装できる。
関連する問題
- TopCoder Member SRM 478 Div1 Hard "RandomApple"
- yukicoder No.155 "生放送とBGM"
- AtCoder Regular Contest 028 D "注文の多い高橋商店" $\sum_{j=0}^{a_i} X^j = (1-X^{a_i+1}) (1-X)^{-1}$と変換できる。
線形漸化式の値
$b_i = a_i (i < k), b_{i+k} = \sum_{j=0}^{k-1} c_j b_{i+j}$と表される線形漸化式を考える。 $f = X^k - \sum_{i=0}^{k-1} c_i X^i$とし、$X^j \bmod f = \sum_{i=0}^{k-1} d_i X^i$と表されたとすると、$b_j = \sum_{i=0}^{k-1} a_i d_i$となる。 これを繰り返し二乗法により計算すれば、線形漸化式のj番目の値を、$O(k^2 \log j)$または$O(M(k) \log j)$程度の計算量で解くことができる。
関連する問題
多項式補間
$f(x_i) = y_i$となるような長さ$k$の列$x, y$が与えられているとする。$i \neq j$なら$x_i \neq x_j$とする。"多項式補間"では、この列から多項式$f$を復元する。 $f \bmod (X-a) = f(a)$である(Polynomial remainder theorem)。 つまり、解きたい式は連立1次合同方程式$f \bmod (X-x_i) = y_i$となる。これを解くには"中国人剰余定理"が適用できる。 $x_i \neq x_j$なら$\gcd(X-x_i,X-x_j) = 1$であることに注意すると、$f \equiv g \pmod{\prod_i (X-x_i)}$となるような$g$が得られる。 $R$が体なら次数$k$未満の多項式でユニークであるので、復元できたといえる。 中国人剰余定理の実装によってそれぞれ"ラグランジュ補間"や"ニュートン補間"が導出できる。
通常$O(n^2)$程度の計算量で補間できるが、等差数列に対してはほぼ線形時間の計算量で補間できる。 また、高速な多項式乗算のアルゴリズムを使って分割統治法方法を行うと$O(M(n) \log n)$程度の計算量で補間多項式が計算できる。
時々、答えの数列が多項式であることはわかっていても実際の多項式を求めるのは難しかったり計算量がかかってしまうことがある。 このとき、適当な数たちに対して、多項式でなく$R$上で計算をして、その後に多項式補間をすることで計算量が改善することがある。
関連する問題
- AtCoder Regular Contest 033 D "見たことのない多項式"
- yukicoder No.42 "貯金箱の溜息"
- TopCoder TCO14 Round 3B Hard "TreeDistance"
彩色多項式
ある無向グラフ$G = (V,E)$に対し、$f(c)$を、このグラフを$c$色以下でproper彩色する場合の数、と定義する。 このとき、$f$は次数$|V|$以下の多項式となっている。
一般のグラフに対して求めるのは難しいが、木やchordal graph, cographなどの特殊なグラフクラスでは効率的に求めることができる。
関連する問題
- HackerRank CodeSprint 5 "Coloring Grid"
- Xmas Contest 2012 Problem C "Colorful Lights"
- NPCA Judge #174 "木上のパスの塗り分け" (自作問題)
Polynomial Identity Test
Schwartz–Zippel lemma。 様々な乱択アルゴリズムにおいて重要な役割を果たしている。(加筆求む)
多項式ハッシュ
長さ$m$の文字列$S$と適当な関数$ord$に対し、多項式$f_S(X) = \sum_{i=0}^{m-1} ord(S_{m-i}) X^i$が定義できる。 これを適当な素数$p$で割った余りを取るとすると$f$はハッシュ関数の族となる。 ただし、$c \neq d$に対して$ord(c) \not\equiv ord(d) \pmod{p}$であり、$ord(c) \not\equiv 0 \pmod{p}$である必要がある。 2つの文字列$S, T (|S| = m, |T| = n)$に対して、ランダムな$B$に対して$f_S(B) \equiv f_T(B) \pmod{p}$となる確率は$\frac{\max(m,n)}{p}$で抑えられる。
このハッシュ関数はハッシュ値のまま様々な操作ができる点で有用である。 例えば、$f_{S T} = X^n f_S + f_T$のようにして文字列連結ができる。 特に文字$c$に対して、$f_{S c} = X f_S + ord(c)$である。 また、$S$の接頭詞$S[1,i)$に対するハッシュを事前計算しておくことによって、$f_{S[i,j)} = f_{S[1,j)} - X^{j-i} f_{S[1,i)}$として部分文字列のハッシュ値を計算できる。
応用は多岐に渡り、文字列検索・LCPの計算など様々なことに利用できる。 多次元にも拡張でき、その場合は多変数多項式になる。 ただし、安易な利用による衝突に関しては、別に記事が必要なほどに落とし穴にはまりやすいので注意すること。