多項式を使うテクニックたち

Latest Author 37zigen /Date 2021-08-07 05:46:36 / Views 16766
19 (Favした一覧ページはユーザーページから)

注意:yukicoderやその他のサイトの問題に対するネタバレがある可能性があります

以下では多項式は可換環であるRRを係数とするとする。 計算量はRR上の基本演算が定数時間でできるとして考える。ただしあまり厳密ではない。 競技プログラミングにおいてはたいていワードサイズのmodを取るので定数時間で計算できるとして問題ない事が多い。

多項式同士の乗算の計算量をM(n)M(n)とする。多項式除算もO(M(n))O(M(n))で計算できる。 単純なアルゴリズムではM(n)O(n2)M(n) \in O(n^2)だが、R=Z/mZR = {\mathbb Z}/m{\mathbb Z}の場合はFFTを用いることでM(n)O(nlognloglogn)M(n) \in O(n \log n \log \log n)にできる。

多項式の総和

ppkk次の多項式とするとき、P(n)=i=0n1p(i)P(n) = \sum_{i=0}^{n-1} p(i)k+1k+1次以下の多項式となる。 i=0n1i=n(n1)2\sum_{i=0}^{n-1} i = \frac{n(n-1)}{2}などの公式として有名だろう。

多項式のある種の逆元

有名なpower seriesの式i=0ai=11a\sum_{i=0}^{\infty} a^i = \frac{1}{1-a}は多項式にも適用できる。 つまり、多項式f=i=0kaiXif = \sum_{i=0}^k a_i X^iに対し、ある種の逆元をi=0(1f)i\sum_{i=0}^{\infty} (1-f)^iと表すことができる。 この式はa0=1a_0 = 1である場合に限りよく定義でき、これは多項式環の拡張である"formal power series"環上に値を取る。

ffa01a_0^{-1}かけることで、つまりf1=a01i=0(1a01f)if^{-1} = a_0^{-1} \sum_{i=0}^{\infty} (1 - a_0^{-1} f)^iとして、a0Ra_0 \in R^*である限りこれを求めることができる。

多項式の平行移動

f(X):=i=0NaiXif(X):=\sum_{i=0}^N a_iX^iCCだけ平行移動したf(X+C)f(X+C)の係数をO(NlogN)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):=i=0Naii!si,exp(Cs):=i=0N(Cs)ii!g(s):=\sum_{i=0}^N a_i i! s^{-i},\exp(Cs):=\sum_{i=0}^N \frac{(Cs)^{i}}{i!}とする。g(s)g(s)exp(Cs)\exp(Cs)の畳み込みになっているのでFFTでO(NlogN)O(N\log{N})で計算できる。 これは平行移動後の関数をラプラス変換したものの逆ラプラス変換Θ(X+C)k=0Nfk(X+C)k=L1[exp(Cs)k=0Nakk!sk+1]\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}}]を計算しているとみなせる(?)。

Πi=1N(1+Xsi)\Pi_{i=1}^{N} (1+X^{s_i})

分割数を計算するときにΠi=1N(1+Xsi)\Pi_{i=1}^{N} (1+X^{s_i})を計算したくなることがある。 https://arxiv.org/abs/1807.11597にて A(X):=Πi=1N(1+Xsi)modXt+1A(X):=\Pi_{i=1}^{N} (1+X^{s_i}) \bmod X^{t+1}O(tlogt)O(t\log t)で求めるアルゴリズムが示されている。 log(1+X)=i=1(1)i1iXi\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} ただし、ai:=#{j:sj=i}a_i:=\#\{j:s_j=i\}とする。O(j=1t[t/j])=O(tlogt)O(\sum_{j=1}^{t}[t/j])=O(t\log t)で計算できる。あとはA(X)=exp(log(A(X))A(X)=\exp(\log(A(X))から計算すればよい。
演習問題

母関数

数列に対し、有理関数が母関数であることと線形漸化式であることは同値である。
・線形漸化式⇒母関数は有理関数
数列{an}n0\{a_{n}\}_{n \geq 0}nMn \geq Mのとき漸化式an=k=1mαkanka_{n}=\sum_{k=1}^{m}α_{k}a_{n−k} で表されているとする。(ただしαkα_{k}は定数かつαm0\alpha_m \neq 0
このとき母関数をffとして h(x):=1k=1mαkxk,g:=hfh(x):=1-\sum_{k=1}^{m}α_{k}x^{k} , g:=hfとする。
ggの各次数の係数について考えれば、MM次以上は全て相殺されるのでggは高々M1M-1次多項式。
hhは定義より明らかにmm次多項式なのでf=g/hf=g/hは有理関数。
・母関数が有理関数⇒線形漸化式
有理関数ffを母関数とする数列{an}n0\{a_{n}\}_{n \geq 0}を考える。
ffは有理関数なので多項式g,hg,hによりf=g/hf=g/hと表せる。
hf=ghf=gの両辺をn(>max{deg g,deg h})n(>\max\{\deg~g,\deg~h\})回微分するとライプニッツ則により
k=0deg h(nk)f(nk)(x)h(k)(x)=0\sum_{k=0}^{\deg~h}\binom nk f^{(n-k)}(x)h^{(k)}(x)=0 ((nk)\binom nkは二項係数)
となるのでx=0x=0を代入し、k=0k=0の項を残して移項すると
f(n)(0)h(0)=k=1deg h(nk)f(nk)(0)h(k)(0)f^{(n)}(0)h(0)=-\sum_{k=1}^{\deg~h}\binom nk f^{(n-k)}(0)h^{(k)}(0)
両辺をh(0)n!h(0)n!で割り、ffのマクローリン展開によりan=f(n)(0)/n!a_{n}=f^{(n)}(0)/n!であることを用いると
an=k=1deg hh(k)(0)/h(0)/k!anka_{n}=-\sum_{k=1}^{\deg~h}h^{(k)}(0)/h(0)/k!*a_{n-k}
ここでh(k)(0)/h(0)/k!h^{(k)}(0)/h(0)/k!nnに依らない定数であるから、これは(deg h)+1(\deg~h)+1項間線形漸化式である

多項式で表せるDP

以下の問題を考える: 「正整数の列aaが与えられるとき、aaの重複なし部分和でちょうどbbになるものは何通りあるか?」 この問題は典型的なDPであるが、以下のように多項式によって表せる: 「f=i(1+Xai)f = \prod_i (1+X^{a_i})とするとき、ffbb次の係数を求めよ」 この多項式はこの問題に関する母関数であるとも考えられる。

また、同じように、「正整数の列aaが与えられるとき、aaの重複あり部分和でちょうどbbになるものは何通りあるか?」という問題の場合、 f=ij=0Xjaif = \prod_i \sum_{j=0}^{\infty} X^{j a_i}となるが、逆元を用いてf=i(1Xai)1f = \prod_i (1-X^{a_i})^{-1}とも表せる。

多次元のDPであっても多変数多項式によって表せ、同じように考えられる。

"戻すDP"

典型的な部分和数え上げ問題のDPの遷移が多項式の掛け算として表せることがわかった。 ならば、その逆演算である割り算がどう適用できるかを考えてみるのは自然だろう。

たとえば、f=i(1+Xai)f = \prod_i (1+X^{a_i})である場合、(1+Xai)(1+X^{a_i})で割ることでDPを"戻す"ことができる。 つまり、aaから要素aia_iを削除した列でのDP結果が得られる。 実際には、(1+Xai)1=j=0(X)aij(1+X^{a_i})^{-1} = \sum_{j=0}^{\infty} (-X)^{a_i j}となる。 単純に再計算する場合O(nb)O(nb)程度の計算量がかかるが、この場合重複あり部分和DPと同じように実装することでO(b)O(b)の計算量で求めることができる。

重複ありの場合、f=i(1Xai)1f = \prod_i (1-X^{a_i})^{-1}であるが、 ((1Xai)1)1=1Xai((1-X^{a_i})^{-1})^{-1} = 1-X^{a_i}というようにそれ自身であるので、"戻す"場合は重複なしDPのような掛け算によって実装できる。

関連する問題

線形漸化式の値

bi=ai(i<k),bi+k=j=0k1cjbi+jb_i = a_i (i < k), b_{i+k} = \sum_{j=0}^{k-1} c_j b_{i+j}と表される線形漸化式を考える。 f=Xki=0k1ciXif = X^k - \sum_{i=0}^{k-1} c_i X^iとし、Xjmodf=i=0k1diXiX^j \bmod f = \sum_{i=0}^{k-1} d_i X^iと表されたとすると、bj=i=0k1aidib_j = \sum_{i=0}^{k-1} a_i d_iとなる。 これを繰り返し二乗法により計算すれば、線形漸化式のj番目の値を、O(k2logj)O(k^2 \log j)またはO(M(k)logj)O(M(k) \log j)程度の計算量で解くことができる。

関連する問題

多項式補間

f(xi)=yif(x_i) = y_iとなるような長さkkの列x,yx, yが与えられているとする。iji \neq jならxixjx_i \neq x_jとする。"多項式補間"では、この列から多項式ffを復元する。 fmod(Xa)=f(a)f \bmod (X-a) = f(a)である(Polynomial remainder theorem)。 つまり、解きたい式は連立1次合同方程式fmod(Xxi)=yif \bmod (X-x_i) = y_iとなる。これを解くには"中国人剰余定理"が適用できる。 xixjx_i \neq x_jならgcd(Xxi,Xxj)=1\gcd(X-x_i,X-x_j) = 1であることに注意すると、fg(modi(Xxi))f \equiv g \pmod{\prod_i (X-x_i)}となるようなggが得られる。 RRが体なら次数kk未満の多項式でユニークであるので、復元できたといえる。 中国人剰余定理の実装によってそれぞれ"ラグランジュ補間"や"ニュートン補間"が導出できる。

通常O(n2)O(n^2)程度の計算量で補間できるが、等差数列に対してはほぼ線形時間の計算量で補間できる。 また、高速な多項式乗算のアルゴリズムを使って分割統治法方法を行うとO(M(n)logn)O(M(n) \log n)程度の計算量で補間多項式が計算できる。

時々、答えの数列が多項式であることはわかっていても実際の多項式を求めるのは難しかったり計算量がかかってしまうことがある。 このとき、適当な数たちに対して、多項式でなくRR上で計算をして、その後に多項式補間をすることで計算量が改善することがある。

関連する問題

彩色多項式

ある無向グラフG=(V,E)G = (V,E)に対し、f(c)f(c)を、このグラフをcc色以下でproper彩色する場合の数、と定義する。 このとき、ffは次数V|V|以下の多項式となっている。

一般のグラフに対して求めるのは難しいが、木やchordal graph, cographなどの特殊なグラフクラスでは効率的に求めることができる。

関連する問題

Polynomial Identity Test

Schwartz–Zippel lemma。 様々な乱択アルゴリズムにおいて重要な役割を果たしている。(加筆求む)

多項式ハッシュ

長さmmの文字列SSと適当な関数ordordに対し、多項式fS(X)=i=0m1ord(Smi)Xif_S(X) = \sum_{i=0}^{m-1} ord(S_{m-i}) X^iが定義できる。 これを適当な素数ppで割った余りを取るとするとffはハッシュ関数の族となる。 ただし、cdc \neq dに対してord(c)≢ord(d)(modp)ord(c) \not\equiv ord(d) \pmod{p}であり、ord(c)≢0(modp)ord(c) \not\equiv 0 \pmod{p}である必要がある。 2つの文字列S,T(S=m,T=n)S, T (|S| = m, |T| = n)に対して、ランダムなBBに対してfS(B)fT(B)(modp)f_S(B) \equiv f_T(B) \pmod{p}となる確率はmax(m,n)p\frac{\max(m,n)}{p}で抑えられる。

このハッシュ関数はハッシュ値のまま様々な操作ができる点で有用である。 例えば、fST=XnfS+fTf_{S T} = X^n f_S + f_Tのようにして文字列連結ができる。 特に文字ccに対して、fSc=XfS+ord(c)f_{S c} = X f_S + ord(c)である。 また、SSの接頭詞S[1,i)S[1,i)に対するハッシュを事前計算しておくことによって、fS[i,j)=fS[1,j)XjifS[1,i)f_{S[i,j)} = f_{S[1,j)} - X^{j-i} f_{S[1,i)}として部分文字列のハッシュ値を計算できる。

応用は多岐に渡り、文字列検索・LCPの計算など様々なことに利用できる。 多次元にも拡張でき、その場合は多変数多項式になる。 ただし、安易な利用による衝突に関しては、別に記事が必要なほどに落とし穴にはまりやすいので注意すること。

関連する問題