AtCoder ARC D: 見たことのない多項式

ガウスジョルダンの消去法などを知っていればO(n^3)で部分点40(/100)、ラグランジュ補間を知っていればO(n^2)で部分点80(/100)をとれる。

ラグランジュ補間を工夫する。

ラグランジュ補間

一般に多項式P(x)についてi!=jのときx[i]!=x[j]ならば

P(x) = Σ[i=0...n]( P(x[i]) * f[i](x)/f[i](x[i]) )

が成り立つ。

ただし、

f[i](x)

= (Π[j=0..n](x-x[j])) / (x-x[i])

= (x-0)*(x-1)*...*(1)*(-1)*...*(x-n)

とする。

この問題は特殊でx[i]の値が0<=x[i]<=nで与えられていると考えればいい。

よってx[i]をiと置き換えて

P(x) = Σ[i=0...n]( P(i) * f[i](x)/f[i](i) )

ただし

f[i](x)

= (Π[j=0..n](x-j)) / (x-i)

= (x-0)*(x-1)*...*(1)*(-1)*...*(x-n)

となる。

とりあえず、自明だが厄介なケースを取り除いておく。

T<=Nとする。このときP(T)は入力として与えられているので、それを出力するだけ。

なので、以下はT>Nを仮定する。

f[i](T)とf[i](i)がすべてのiについて求まればよい。

f[i](T) = (Π[j=0...n](T-j)) / (T-i)

である。

T>NよりT-j>0が成り立つ。

S=Π[j=0...n](T-j)

として総乗を事前に計算しておけば

f[i](T) = S/(T-i)

のようにO(log(mod))でf[i](T)を求めることができる。

次に、f[i](i)について考えてみる。

f[0](0)をO(N)で求めておく。

f[i](i)からf[i+1](i+1)を計算したい。

f[i](i)

= (i-0)*(i-1)*(i-2)*...*1*(-1)*...*(i-(n-1))*(i-n)

f[i](i+1)

= ( (i+1)-0)*( (i+1)-1)*...*1*(-1)*...*( (i+1)-(n-1))*( (i+1)-n)

f[i](i)とf[i](i+1)の共通点を見てみると、n値の積になっていて、0を除くすべての要素が連続して存在する。

よって1*(-1)から両端にどう延びていくかだけが違いになるが、

前者は左にiまで右にi-nまで、後者は左にi+1まで右にi+1-nまでとなっている。

ここから

f[i](i+1) = f[i]*(i+1) / (i-n)

となる。

これにより、O(log(mod) )でf[i](i+1)を求まる。

以上から、全体で

O(nlog(mod) )

で間に合う。