Перейти до основного вмісту

Операції над многочленами та рядами

Задачі зі змагального програмування, особливо ті, що так чи інакше пов'язані з перелічуванням, часто розв'язуються зведенням задачі до обчислення чогось над многочленами та формальними степеневими рядами.

Сюди входять такі поняття, як множення многочленів, інтерполяція, а також складніші — наприклад, логарифми та експоненти многочленів. У цій статті подано короткий огляд таких операцій та поширених підходів до них.

Базові поняття та факти

У цьому розділі ми зосереджуємося радше на означеннях та «інтуїтивних» властивостях різних операцій над многочленами. Технічні деталі їхньої реалізації та складності будуть розглянуті в подальших розділах.

Множення многочленів

Означення

Многочлен від однієї змінної — це вираз вигляду A(x)=a0+a1x++anxnA(x) = a_0 + a_1 x + \dots + a_n x^n.

Значення a0,,ana_0, \dots, a_n — це коефіцієнти многочлена, які зазвичай беруться з деякої множини чисел або числоподібних структур. У цій статті ми припускаємо, що коефіцієнти беруться з деякого поля, тобто операції додавання, віднімання, множення та ділення для них коректно визначені (окрім ділення на 00) і вони загалом поводяться подібно до дійсних чисел.

Типовий приклад такого поля — поле остач за простим модулем pp.

Для простоти ми опускатимемо слова від однієї змінної, оскільки це єдиний вид многочленів, який ми розглядаємо в цій статті. Ми також писатимемо AA замість A(x)A(x) скрізь, де це можливо, що буде зрозуміло з контексту. Припускається, що або an0a_n \neq 0, або A(x)=0A(x)=0.

Означення

Добутком двох многочленів є вираз, отриманий розкриттям дужок як арифметичного виразу:

A(x)B(x)=(i=0naixi)(j=0mbjxj)=i,jaibjxi+j=k=0n+mckxk=C(x).A(x) B(x) = \left(\sum\limits_{i=0}^n a_i x^i \right)\left(\sum\limits_{j=0}^m b_j x^j\right) = \sum\limits_{i,j} a_i b_j x^{i+j} = \sum\limits_{k=0}^{n+m} c_k x^k = C(x).

Послідовність c0,c1,,cn+mc_0, c_1, \dots, c_{n+m} коефіцієнтів C(x)C(x) називається згорткою послідовностей a0,,ana_0, \dots, a_n та b0,,bmb_0, \dots, b_m.

Означення

Степінь многочлена AA з an0a_n \neq 0 визначається як degA=n\deg A = n.

Для узгодженості степінь A(x)=0A(x) = 0 визначається як degA=\deg A = -\infty.

У такому означенні degAB=degA+degB\deg AB = \deg A + \deg B для будь-яких многочленів AA та BB.

Згортки лежать в основі розв'язання багатьох перелічувальних задач.

інформація

У вас є nn об'єктів першого типу та mm об'єктів другого типу.

Об'єкти першого типу мають значення a1,,ana_1, \dots, a_n, а об'єкти другого типу — значення b1,,bmb_1, \dots, b_m.

Ви вибираєте один об'єкт першого типу та один об'єкт другого типу. Скількома способами можна отримати сумарне значення kk?

Розв'язок

Розглянемо добуток (xa1++xan)(xb1++xbm)(x^{a_1} + \dots + x^{a_n})(x^{b_1} + \dots + x^{b_m}). Якщо розкрити дужки, кожен одночлен відповідатиме парі (ai,bj)(a_i, b_j) і даватиме внесок у коефіцієнт біля xai+bjx^{a_i+b_j}. Іншими словами, відповіддю є коефіцієнт біля xkx^k у добутку.

інформація

Ви кидаєте 66-гранний кубик nn разів і підсумовуєте результати всіх кидків. Яка ймовірність отримати суму kk?

Розв'язок

Відповідь — це кількість результатів, що мають суму kk, поділена на загальну кількість результатів, яка дорівнює 6n6^n.

Яка кількість результатів, що мають суму kk? Для n=1n=1 її можна подати многочленом A(x)=x1+x2++x6A(x) = x^1+x^2+\dots+x^6.

Для n=2n=2, використовуючи той самий підхід, що й у прикладі вище, ми робимо висновок, що вона подається многочленом (x1+x2++x6)2(x^1+x^2+\dots+x^6)^2.

Зважаючи на це, відповіддю на задачу є kk-й коефіцієнт многочлена (x1+x2++x6)n(x^1+x^2+\dots+x^6)^n, поділений на 6n6^n.

Коефіцієнт біля xkx^k у многочлені A(x)A(x) коротко позначається як [xk]A[x^k]A.

Формальний степеневий ряд

Означення

Формальний степеневий ряд — це нескінченна сума A(x)=a0+a1x+a2x2+A(x) = a_0 + a_1 x + a_2 x^2 + \dots, що розглядається безвідносно до її властивостей збіжності.

Іншими словами, коли ми розглядаємо, наприклад, суму 1+12+14+18+=21+\frac{1}{2}+\frac{1}{4}+\frac{1}{8}+\dots=2, ми маємо на увазі, що вона збігається до 22, коли кількість доданків прямує до нескінченності. Однак формальні ряди розглядаються лише в термінах послідовностей, які їх утворюють.

Означення

Добуток формальних степеневих рядів A(x)A(x) та B(x)B(x) також визначається розкриттям дужок як арифметичного виразу:

A(x)B(x)=(i=0aixi)(j=0bjxj)=i,jaibjxi+j=k=0ckxk=C(x),A(x) B(x) = \left(\sum\limits_{i=0}^\infty a_i x^i \right)\left(\sum\limits_{j=0}^\infty b_j x^j\right) = \sum\limits_{i,j} a_i b_j x^{i+j} = \sum\limits_{k=0}^{\infty} c_k x^k = C(x),

де коефіцієнти c0,c1,c_0, c_1, \dots визначаються як скінченні суми

ck=i=0kaibki.c_k = \sum\limits_{i=0}^k a_i b_{k-i}.

Послідовність c0,c1,c_0, c_1, \dots також називається згорткою послідовностей a0,a1,a_0, a_1, \dots та b0,b1,b_0, b_1, \dots, узагальнюючи це поняття на нескінченні послідовності.

Отже, многочлени можна розглядати як формальні степеневі ряди, але зі скінченною кількістю коефіцієнтів.

Формальні степеневі ряди відіграють вирішальну роль у перелічувальній комбінаториці, де їх вивчають як твірні функції для різних послідовностей. Детальне пояснення твірних функцій та інтуїції за ними, на жаль, виходить за межі цієї статті, тому допитливого читача відсилаємо, наприклад, сюди за деталями про їхній комбінаторний зміст.

Однак ми дуже стисло зазначимо, що якщо A(x)A(x) та B(x)B(x) — це твірні функції для послідовностей, що перелічують деякі об'єкти за кількістю «атомів» у них (наприклад, дерева за кількістю вершин), то добуток A(x)B(x)A(x) B(x) перелічує об'єкти, які можна описати як пари об'єктів типів AA та BB, перелічуючи їх за загальною кількістю «атомів» у парі.

інформація

Нехай A(x)=i=02ixiA(x) = \sum\limits_{i=0}^\infty 2^i x^i перелічує набори каменів, кожен камінь у яких пофарбований в один з 22 кольорів (тож існує 2i2^i таких наборів розміру ii), а B(x)=j=03jxjB(x) = \sum\limits_{j=0}^{\infty} 3^j x^j перелічує набори каменів, кожен камінь у яких пофарбований в один з 33 кольорів. Тоді C(x)=A(x)B(x)=k=0ckxkC(x) = A(x) B(x) = \sum\limits_{k=0}^\infty c_k x^k перелічуватиме об'єкти, які можна описати як «два набори каменів, перший набір лише з каменів типу AA, другий набір лише з каменів типу BB, із загальною кількістю каменів kk» для ckc_k.

Подібним чином є інтуїтивний зміст і в деяких інших функцій над формальними степеневими рядами.

Ділення многочленів стовпчиком

Подібно до цілих чисел, для многочленів можна визначити ділення стовпчиком.

Означення

Для будь-яких многочленів AA та B0B \neq 0 можна подати AA у вигляді

A=DB+R, degR<degB,A = D \cdot B + R,~ \deg R < \deg B,

де RR називається остачею від ділення AA на BB, а DD називається часткою.

Позначаючи degA=n\deg A = n та degB=m\deg B = m, наївний спосіб зробити це — застосувати ділення стовпчиком, під час якого ми множимо BB на одночлен anbmxnm\frac{a_n}{b_m} x^{n - m} і віднімаємо результат від AA, доки степінь AA не стане меншим за степінь BB. Те, що залишиться від AA наприкінці, буде остачею (звідси й назва), а многочлени, на які ми множили BB у процесі, підсумовані разом, утворюють частку.

Означення

Якщо AA та BB мають однакову остачу за модулем CC, то кажуть, що вони еквівалентні за модулем CC, що позначається як

AB(modC).A \equiv B \pmod{C}.

Ділення многочленів стовпчиком корисне завдяки своїм численним важливим властивостям:

  • AA кратне BB тоді й лише тоді, коли A0(modB)A \equiv 0 \pmod B.

  • Звідси випливає, що AB(modC)A \equiv B \pmod C тоді й лише тоді, коли ABA-B кратне CC.

  • Зокрема, AB(modCD)A \equiv B \pmod{C \cdot D} тягне за собою AB(modC)A \equiv B \pmod{C}.

  • Для будь-якого лінійного многочлена xrx-r виконується A(x)A(r)(modxr)A(x) \equiv A(r) \pmod{x-r}.

  • Звідси випливає, що AA кратне xrx-r тоді й лише тоді, коли A(r)=0A(r)=0.

  • Для модуля xkx^k виконується Aa0+a1x++ak1xk1(modxk)A \equiv a_0 + a_1 x + \dots + a_{k-1} x^{k-1} \pmod{x^k}.

Зауважимо, що ділення стовпчиком не можна коректно визначити для формальних степеневих рядів. Натомість для будь-якого A(x)A(x) такого, що a00a_0 \neq 0, можна визначити обернений формальний степеневий ряд A1(x)A^{-1}(x) такий, що A(x)A1(x)=1A(x) A^{-1}(x) = 1. Цей факт, своєю чергою, можна використати для обчислення результату ділення многочленів стовпчиком.

Базова реалізація

Тут ви можете знайти базову реалізацію алгебри многочленів.

Вона підтримує всі тривіальні операції та деякі інші корисні методи. Головний клас — poly<T> для многочленів з коефіцієнтами типу T.

Підтримуються всі арифметичні операції +, -, *, % та /, де % та / позначають остачу та частку в евклідовому діленні.

Також є клас modular<m> для виконання арифметичних операцій над остачами за простим модулем m.

Інші корисні функції:

  • deriv(): обчислює похідну P(x)P'(x) від P(x)P(x).
  • integr(): обчислює невизначений інтеграл Q(x)=P(x)Q(x) = \int P(x) від P(x)P(x) такий, що Q(0)=0Q(0)=0.
  • inv(size_t n): обчислює перші nn коефіцієнтів P1(x)P^{-1}(x) за O(nlogn)O(n \log n).
  • log(size_t n): обчислює перші nn коефіцієнтів lnP(x)\ln P(x) за O(nlogn)O(n \log n).
  • exp(size_t n): обчислює перші nn коефіцієнтів expP(x)\exp P(x) за O(nlogn)O(n \log n).
  • pow(size_t k, size_t n): обчислює перші nn коефіцієнтів Pk(x)P^{k}(x) за O(nlognk)O(n \log nk).
  • deg(): повертає степінь P(x)P(x).
  • lead(): повертає коефіцієнт біля xdegP(x)x^{\deg P(x)}.
  • resultant(poly<T> a, poly<T> b): обчислює результант aa та bb за O(ab)O(|a| \cdot |b|).
  • bpow(T x, size_t n): обчислює xnx^n.
  • bpow(T x, size_t n, T m): обчислює xn(modm)x^n \pmod{m}.
  • chirpz(T z, size_t n): обчислює P(1),P(z),P(z2),,P(zn1)P(1), P(z), P(z^2), \dots, P(z^{n-1}) за O(nlogn)O(n \log n).
  • vector<T> eval(vector<T> x): обчислює P(x1),,P(xn)P(x_1), \dots, P(x_n) за O(nlog2n)O(n \log^2 n).
  • poly<T> inter(vector<T> x, vector<T> y): інтерполює многочлен за набором пар P(xi)=yiP(x_i) = y_i за O(nlog2n)O(n \log^2 n).
  • І ще деякі — не соромтеся досліджувати код!

Арифметика

Множення

Найголовніша операція — це множення двох многочленів. Тобто, маючи многочлени AA та BB:

A=a0+a1x++anxnA = a_0 + a_1 x + \dots + a_n x^n B=b0+b1x++bmxmB = b_0 + b_1 x + \dots + b_m x^m

потрібно обчислити многочлен C=ABC = A \cdot B, який визначається як

C=i=0nj=0maibjxi+j=c0+c1x++cn+mxn+m.\boxed{C = \sum\limits_{i=0}^n \sum\limits_{j=0}^m a_i b_j x^{i+j}} = c_0 + c_1 x + \dots + c_{n+m} x^{n+m}.

Його можна обчислити за O(nlogn)O(n \log n) за допомогою швидкого перетворення Фур'є, і майже всі методи тут використовуватимуть його як підпрограму.

Обернений ряд

Якщо A(0)0A(0) \neq 0, то завжди існує нескінченний формальний степеневий ряд A1(x)=q0+q1x+q2x2+A^{-1}(x) = q_0+q_1 x + q_2 x^2 + \dots такий, що A1A=1A^{-1} A = 1. Часто буває корисно обчислити перші kk коефіцієнтів A1A^{-1} (тобто обчислити його за модулем xkx^k). Є два основні способи зробити це.

«Розділяй і володарюй»

Цей алгоритм був згаданий у статті Шьонхаге і натхненний методом Греффе. Відомо, що для B(x)=A(x)A(x)B(x)=A(x)A(-x) виконується B(x)=B(x)B(x)=B(-x), тобто B(x)B(x) — парний многочлен. Це означає, що він має ненульові коефіцієнти лише при парних номерах і може бути поданий як B(x)=T(x2)B(x)=T(x^2). Таким чином, ми можемо зробити такий перехід:

A1(x)1A(x)A(x)A(x)A(x)A(x)T(x2)(modxk)A^{-1}(x) \equiv \frac{1}{A(x)} \equiv \frac{A(-x)}{A(x)A(-x)} \equiv \frac{A(-x)}{T(x^2)} \pmod{x^k}

Зауважимо, що T(x)T(x) можна обчислити за допомогою одного множення, після чого нас цікавить лише перша половина коефіцієнтів його оберненого ряду. Це фактично зводить початкову задачу обчислення A1(modxk)A^{-1} \pmod{x^k} до обчислення T1(modxk/2)T^{-1} \pmod{x^{\lceil k / 2 \rceil}}.

Складність цього методу можна оцінити як

T(n)=T(n/2)+O(nlogn)=O(nlogn).T(n) = T(n/2) + O(n \log n) = O(n \log n).

Алгоритм Зівекінга–Кунга

Загальний процес, описаний тут, відомий як підняття Гензеля, оскільки він випливає з леми Гензеля. Ми розглянемо його детальніше далі, а поки що зосередимося на спеціальному розв'язку. Частина «підняття» тут означає, що ми починаємо з наближення B0=q0=a01B_0=q_0=a_0^{-1}, яке є A1(modx)A^{-1} \pmod x, а потім ітеративно піднімаємося від modxa\bmod x^a до modx2a\bmod x^{2a}.

Нехай BkA1(modxa)B_k \equiv A^{-1} \pmod{x^a}. Наступне наближення має задовольняти рівняння ABk+11(modx2a)A B_{k+1} \equiv 1 \pmod{x^{2a}} і може бути подане як Bk+1=Bk+xaCB_{k+1} = B_k + x^a C. Звідси випливає рівняння

A(Bk+xaC)1(modx2a).A(B_k + x^{a}C) \equiv 1 \pmod{x^{2a}}.

Нехай ABk1+xaD(modx2a)A B_k \equiv 1 + x^a D \pmod{x^{2a}}, тоді рівняння вище тягне за собою

xa(D+AC)0(modx2a)    DAC(modxa)    CBkD(modxa).x^a(D+AC) \equiv 0 \pmod{x^{2a}} \implies D \equiv -AC \pmod{x^a} \implies C \equiv -B_k D \pmod{x^a}.

Звідси можна отримати остаточну формулу, яка має вигляд

xaCBkxaDBk(1ABk)(modx2a)    Bk+1Bk(2ABk)(modx2a)x^a C \equiv -B_k x^a D \equiv B_k(1-AB_k) \pmod{x^{2a}} \implies \boxed{B_{k+1} \equiv B_k(2-AB_k) \pmod{x^{2a}}}

Отже, почавши з B0a01(modx)B_0 \equiv a_0^{-1} \pmod x, ми обчислимо послідовність BkB_k таку, що ABk1(modx2k)AB_k \equiv 1 \pmod{x^{2^k}}, зі складністю

T(n)=T(n/2)+O(nlogn)=O(nlogn).T(n) = T(n/2) + O(n \log n) = O(n \log n).

Алгоритм тут може здатися дещо складнішим за перший, але за ним стоїть дуже ґрунтовне й практичне обґрунтування, а також великий потенціал до узагальнення, якщо подивитися на нього з іншого боку, що буде пояснено далі.

Евклідове ділення

Розглянемо два многочлени A(x)A(x) та B(x)B(x) степенів nn та mm. Як було сказано раніше, A(x)A(x) можна переписати як

A(x)=B(x)D(x)+R(x),degR<degB.A(x) = B(x) D(x) + R(x), \deg R < \deg B.

Нехай nmn \geq m, це означало б, що degD=nm\deg D = n - m і старші nm+1n-m+1 коефіцієнтів AA не впливають на RR. Це означає, що D(x)D(x) можна відновити зі старших nm+1n-m+1 коефіцієнтів A(x)A(x) та B(x)B(x), якщо розглянути це як систему рівнянь.

Систему лінійних рівнянь, про яку йдеться, можна записати в такому вигляді:

[anam+1am]=[bm00bm0bm1bm][dnmd1d0]\begin{bmatrix} a_n \\ \vdots \\ a_{m+1} \\ a_{m} \end{bmatrix} = \begin{bmatrix} b_m & \dots & 0 & 0 \\ \vdots & \ddots & \vdots & \vdots \\ \dots & \dots & b_m & 0 \\ \dots & \dots & b_{m-1} & b_m \end{bmatrix} \begin{bmatrix}d_{n-m} \\ \vdots \\ d_1 \\ d_0\end{bmatrix}

З цього вигляду можна зробити висновок, що з введенням обернених многочленів

AR(x)=xnA(x1)=an+an1x++a0xnA^R(x) = x^nA(x^{-1})= a_n + a_{n-1} x + \dots + a_0 x^n BR(x)=xmB(x1)=bm+bm1x++b0xmB^R(x) = x^m B(x^{-1}) = b_m + b_{m-1} x + \dots + b_0 x^m DR(x)=xnmD(x1)=dnm+dnm1x++d0xnmD^R(x) = x^{n-m}D(x^{-1}) = d_{n-m} + d_{n-m-1} x + \dots + d_0 x^{n-m}

систему можна переписати як

AR(x)BR(x)DR(x)(modxnm+1).A^R(x) \equiv B^R(x) D^R(x) \pmod{x^{n-m+1}}.

Звідси можна однозначно відновити всі коефіцієнти D(x)D(x):

DR(x)AR(x)(BR(x))1(modxnm+1)\boxed{D^R(x) \equiv A^R(x) (B^R(x))^{-1} \pmod{x^{n-m+1}}}

А з цього, своєю чергою, можна відновити R(x)R(x) як R(x)=A(x)B(x)D(x)R(x) = A(x) - B(x)D(x).

Зауважимо, що матриця вище — це так звана трикутна матриця Тепліца, і, як ми бачимо, розв'язання системи лінійних рівнянь з довільною матрицею Тепліца насправді еквівалентне оберненню многочлена. Більше того, обернена до неї матриця також буде трикутною матрицею Тепліца, а її елементи, у термінах, що використовувалися вище, є коефіцієнтами (BR(x))1(modxnm+1)(B^R(x))^{-1} \pmod{x^{n-m+1}}.

Обчислення функцій від многочлена

Метод Ньютона

Узагальнимо алгоритм Зівекінга–Кунга. Розглянемо рівняння F(P)=0F(P) = 0, де P(x)P(x) має бути многочленом, а F(x)F(x) — деяка функція зі значеннями-многочленами, визначена як

F(x)=i=0αi(xβ)i,F(x) = \sum\limits_{i=0}^\infty \alpha_i (x-\beta)^i,

де β\beta — деяка константа. Можна довести, що, ввівши нову формальну змінну yy, ми можемо виразити F(x)F(x) як

F(x)=F(y)+(xy)F(y)+(xy)2G(x,y),F(x) = F(y) + (x-y)F'(y) + (x-y)^2 G(x,y),

де F(x)F'(x) — формальний степеневий ряд похідної, визначений як

F(x)=i=0(i+1)αi+1(xβ)i,F'(x) = \sum\limits_{i=0}^\infty (i+1)\alpha_{i+1}(x-\beta)^i,

а G(x,y)G(x, y) — деякий формальний степеневий ряд від xx та yy. З цим результатом ми можемо знайти розв'язок ітеративно.

Нехай F(Qk)0(modxa)F(Q_k) \equiv 0 \pmod{x^{a}}. Нам потрібно знайти Qk+1Qk+xaC(modx2a)Q_{k+1} \equiv Q_k + x^a C \pmod{x^{2a}} такий, що F(Qk+1)0(modx2a)F(Q_{k+1}) \equiv 0 \pmod{x^{2a}}.

Підставивши x=Qk+1x = Q_{k+1} та y=Qky=Q_k у формулу вище, ми отримуємо

F(Qk+1)F(Qk)+(Qk+1Qk)F(Qk)+(Qk+1Qk)2G(x,y)(modx)2a.F(Q_{k+1}) \equiv F(Q_k) + (Q_{k+1} - Q_k) F'(Q_k) + (Q_{k+1} - Q_k)^2 G(x, y) \pmod x^{2a}.

Оскільки Qk+1Qk0(modxa)Q_{k+1} - Q_k \equiv 0 \pmod{x^a}, то також виконується (Qk+1Qk)20(modx2a)(Q_{k+1} - Q_k)^2 \equiv 0 \pmod{x^{2a}}, тому

0F(Qk+1)F(Qk)+(Qk+1Qk)F(Qk)(modx2a).0 \equiv F(Q_{k+1}) \equiv F(Q_k) + (Q_{k+1} - Q_k) F'(Q_k) \pmod{x^{2a}}.

Остання формула дає нам значення Qk+1Q_{k+1}:

Qk+1=QkF(Qk)F(Qk)(modx2a)\boxed{Q_{k+1} = Q_k - \dfrac{F(Q_k)}{F'(Q_k)} \pmod{x^{2a}}}

Отже, знаючи, як обертати многочлени та як обчислювати F(Qk)F(Q_k), ми можемо знайти nn коефіцієнтів PP зі складністю

T(n)=T(n/2)+f(n),T(n) = T(n/2) + f(n),

де f(n)f(n) — час, потрібний для обчислення F(Qk)F(Q_k) та F(Qk)1F'(Q_k)^{-1}, який зазвичай становить O(nlogn)O(n \log n).

Ітеративне правило вище відоме в чисельному аналізі як метод Ньютона.

Лема Гензеля

Як було згадано раніше, формально й у загальному вигляді цей результат відомий як лема Гензеля, і її насправді можна використовувати в ще ширшому сенсі, коли ми працюємо з послідовністю вкладених кілець. У цьому конкретному випадку ми працювали з послідовністю остач многочленів за модулями xx, x2x^2, x3x^3 і так далі.

Інший приклад, де підняття Гензеля може бути корисним, — це так звані pp-адичні числа, де ми фактично працюємо з послідовністю остач цілих чисел за модулями pp, p2p^2, p3p^3 і так далі. Наприклад, метод Ньютона можна використати, щоб знайти всі можливі автоморфні числа (числа, які закінчуються самі на себе при піднесенні до квадрата) із заданою основою системи числення. Цю задачу залишаємо читачеві як вправу. Ви можете розглянути цю задачу, щоб перевірити, чи працює ваш розв'язок для чисел з основою 1010.

Логарифм

Для функції lnP(x)\ln P(x) відомо, що:

(lnP(x))=P(x)P(x)\boxed{(\ln P(x))' = \dfrac{P'(x)}{P(x)}}

Таким чином, ми можемо обчислити nn коефіцієнтів lnP(x)\ln P(x) за O(nlogn)O(n \log n).

Обернений ряд

Виявляється, ми можемо отримати формулу для A1A^{-1} за допомогою методу Ньютона. Для цього ми беремо рівняння A=Q1A=Q^{-1}, отже:

F(Q)=Q1AF(Q) = Q^{-1} - A F(Q)=Q2F'(Q) = -Q^{-2} Qk+1Qk(2AQk)(modx2k+1)\boxed{Q_{k+1} \equiv Q_k(2-AQ_k) \pmod{x^{2^{k+1}}}}

Експонента

Навчимося обчислювати eP(x)=Q(x)e^{P(x)}=Q(x). Має виконуватися lnQ=P\ln Q = P, отже:

F(Q)=lnQPF(Q) = \ln Q - P F(Q)=Q1F'(Q) = Q^{-1} Qk+1Qk(1+PlnQk)(modx2k+1)\boxed{Q_{k+1} \equiv Q_k(1 + P - \ln Q_k) \pmod{x^{2^{k+1}}}}

kk-й степінь

Тепер нам потрібно обчислити Pk(x)=QP^k(x)=Q. Це можна зробити за допомогою такої формули:

Q=exp[klnP(x)]Q = \exp\left[k \ln P(x)\right]

Зауважте, однак, що ви можете правильно обчислити логарифми та експоненти лише тоді, коли можете знайти деяке початкове Q0Q_0.

Щоб його знайти, потрібно обчислити логарифм або експоненту вільного коефіцієнта многочлена.

Але єдиний розумний спосіб це зробити — якщо P(0)=1P(0)=1 для Q=lnPQ = \ln P, тоді Q(0)=0Q(0)=0, і якщо P(0)=0P(0)=0 для Q=ePQ = e^P, тоді Q(0)=1Q(0)=1.

Отже, формулу вище можна використовувати лише якщо P(0)=1P(0) = 1. Інакше, якщо P(x)=αxtT(x)P(x) = \alpha x^t T(x), де T(0)=1T(0)=1, можна записати, що:

Pk(x)=αkxktexp[klnT(x)]\boxed{P^k(x) = \alpha^kx^{kt} \exp[k \ln T(x)]}

Зауважте, що ви також можете обчислити деякий корінь kk-го степеня з многочлена, якщо можете обчислити αk\sqrt[k]{\alpha}, наприклад для α=1\alpha=1.

Обчислення в точках та інтерполяція

Chirp-z перетворення

Для окремого випадку, коли вам потрібно обчислити многочлен у точках xr=z2rx_r = z^{2r}, можна зробити таке:

A(z2r)=k=0nakz2krA(z^{2r}) = \sum\limits_{k=0}^n a_k z^{2kr}

Підставимо 2kr=r2+k2(rk)22kr = r^2+k^2-(r-k)^2. Тоді ця сума переписується як:

A(z2r)=zr2k=0n(akzk2)z(rk)2\boxed{A(z^{2r}) = z^{r^2}\sum\limits_{k=0}^n (a_k z^{k^2}) z^{-(r-k)^2}}

Що, з точністю до множника zr2z^{r^2}, дорівнює згортці послідовностей uk=akzk2u_k = a_k z^{k^2} та vk=zk2v_k = z^{-k^2}.

Зауважте, що тут uku_k має індекси від 00 до nn, а vkv_k має індекси від n-n до mm, де mm — максимальний степінь zz, який вам потрібен.

Тепер, якщо вам потрібно обчислити многочлен у точках xr=z2r+1x_r = z^{2r+1}, ви можете звести це до попередньої задачі за допомогою перетворення akakzka_k \to a_k z^k.

Це дає нам алгоритм за O(nlogn)O(n \log n), коли вам потрібно обчислити значення в степенях zz, тож ви можете обчислити DFT для розмірів, що не є степенями двійки.

Інше спостереження полягає в тому, що kr=(k+r2)(k2)(r2)kr = \binom{k+r}{2} - \binom{k}{2} - \binom{r}{2}. Тоді маємо

A(zr)=z(r2)k=0n(akz(k2))z(k+r2)\boxed{A(z^r) = z^{-\binom{r}{2}}\sum\limits_{k=0}^n \left(a_k z^{-\binom{k}{2}}\right)z^{\binom{k+r}{2}}}

Коефіцієнт біля xn+rx^{n+r} у добутку многочленів A0(x)=k=0nankz(nk2)xkA_0(x) = \sum\limits_{k=0}^n a_{n-k}z^{-\binom{n-k}{2}}x^k та A1(x)=k0z(k2)xkA_1(x) = \sum\limits_{k\geq 0}z^{\binom{k}{2}}x^k дорівнює z(r2)A(zr)z^{\binom{r}{2}}A(z^r). Для обчислення коефіцієнтів A0(x)A_0(x) та A1(x)A_1(x) можна використати формулу z(k+12)=z(k2)+kz^{\binom{k+1}{2}}=z^{\binom{k}{2}+k}.

Обчислення в багатьох точках

Припустимо, вам потрібно обчислити A(x1),,A(xn)A(x_1), \dots, A(x_n). Як було згадано раніше, A(x)A(xi)(modxxi)A(x) \equiv A(x_i) \pmod{x-x_i}. Таким чином, можна зробити таке:

  1. Побудувати дерево відрізків таке, що у відрізку [l,r)[l,r) стоїть добуток Pl,r(x)=(xxl)(xxl+1)(xxr1)P_{l, r}(x) = (x-x_l)(x-x_{l+1})\dots(x-x_{r-1}).
  2. Починаючи з l=1l=1 та r=n+1r=n+1 у корені. Нехай m=(l+r)/2m=\lfloor(l+r)/2\rfloor. Спускаємося до [l,m)[l,m) з многочленом A(x)(modPl,m(x))A(x) \pmod{P_{l,m}(x)}.
  3. Це рекурсивно обчислить A(xl),,A(xm1)A(x_l), \dots, A(x_{m-1}), тепер зробимо те саме для [m,r)[m,r) з A(x)(modPm,r(x))A(x) \pmod{P_{m,r}(x)}.
  4. Об'єднати результати першого та другого рекурсивних викликів і повернути їх.

Уся процедура виконається за O(nlog2n)O(n \log^2 n).

Інтерполяція

Існує пряма формула Лагранжа для інтерполяції многочлена за заданим набором пар (xi,yi)(x_i, y_i):

A(x)=i=1nyijixxjxixj\boxed{A(x) = \sum\limits_{i=1}^n y_i \prod\limits_{j \neq i}\dfrac{x-x_j}{x_i - x_j}}

Обчислити її напряму важко, але виявляється, що ми можемо обчислити її за O(nlog2n)O(n \log^2 n) за допомогою підходу «розділяй і володарюй»:

Розглянемо P(x)=(xx1)(xxn)P(x) = (x-x_1)\dots(x-x_n). Щоб знати коефіцієнти знаменників у A(x)A(x), ми маємо обчислити добутки на кшталт:

Pi=ji(xixj)P_i = \prod\limits_{j \neq i} (x_i-x_j)

Але якщо розглянути похідну P(x)P'(x), то виявиться, що P(xi)=PiP'(x_i) = P_i. Таким чином, можна обчислити PiP_i за допомогою обчислення в точках за O(nlog2n)O(n \log^2 n).

Тепер розглянемо рекурсивний алгоритм, виконаний на тому самому дереві відрізків, що й в обчисленні в багатьох точках. Він починається в листках зі значенням yiPi\dfrac{y_i}{P_i} у кожному листку.

Коли ми повертаємося з рекурсії, ми маємо об'єднати результати з лівої та правої вершин як Al,r=Al,mPm,r+Pl,mAm,rA_{l,r} = A_{l,m}P_{m,r} + P_{l,m} A_{m,r}.

Таким чином, коли ви повернетеся до кореня, ви матимете в ньому саме A(x)A(x). Уся процедура також працює за O(nlog2n)O(n \log^2 n).

НСД та результанти

Припустимо, вам дано многочлени A(x)=a0+a1x++anxnA(x) = a_0 + a_1 x + \dots + a_n x^n та B(x)=b0+b1x++bmxmB(x) = b_0 + b_1 x + \dots + b_m x^m.

Нехай λ0,,λn\lambda_0, \dots, \lambda_n — корені A(x)A(x), а μ0,,μm\mu_0, \dots, \mu_m — корені B(x)B(x), пораховані з урахуванням їхньої кратності.

Ви хочете дізнатися, чи мають A(x)A(x) та B(x)B(x) якісь спільні корені. Є два взаємопов'язані способи зробити це.

Алгоритм Евкліда

Що ж, у нас уже є стаття про нього. Для довільної області цілісності алгоритм Евкліда можна записати настільки просто:

template<typename T>
T gcd(const T &a, const T &b) {
return b == T(0) ? a : gcd(b, a % b);
}

Можна довести, що для многочленів A(x)A(x) та B(x)B(x) він працюватиме за O(nm)O(nm).

Результант

Обчислимо добуток A(μ0)A(μm)A(\mu_0)\cdots A(\mu_m). Він дорівнюватиме нулю тоді й лише тоді, коли якесь μi\mu_i є коренем A(x)A(x).

Для симетрії ми також можемо домножити його на bmnb_m^n і переписати весь добуток у такому вигляді:

R(A,B)=bmnj=0mA(μj)=bmnamni=0nj=0m(μjλi)=(1)mnanmi=0nB(λi)\boxed{\mathcal{R}(A, B) = b_m^n\prod\limits_{j=0}^m A(\mu_j) = b_m^n a_m^n \prod\limits_{i=0}^n \prod\limits_{j=0}^m (\mu_j - \lambda_i)= (-1)^{mn}a_n^m \prod\limits_{i=0}^n B(\lambda_i)}

Значення, визначене вище, називається результантом многочленів A(x)A(x) та B(x)B(x). З означення можна вивести такі властивості:

  1. R(A,B)=(1)nmR(B,A)\mathcal R(A, B) = (-1)^{nm} \mathcal R(B, A).
  2. R(A,B)=anmbmn\mathcal R(A, B)= a_n^m b_m^n, коли n=0n=0 або m=0m=0.
  3. Якщо bm=1b_m=1, то R(ACB,B)=R(A,B)\mathcal R(A - CB, B) = \mathcal R(A, B) для довільного многочлена C(x)C(x) та n,m1n,m \geq 1.
  4. Звідси випливає R(A,B)=bmdeg(A)deg(ACB)R(ACB,B)\mathcal R(A, B) = b_m^{\deg(A) - \deg(A-CB)}\mathcal R(A - CB, B) для довільних A(x)A(x), B(x)B(x), C(x)C(x).

Дивовижним чином це означає, що результант двох многочленів насправді завжди належить тому самому кільцю, що й їхні коефіцієнти!

Також ці властивості дозволяють нам обчислювати результант разом із алгоритмом Евкліда, що працює за O(nm)O(nm).

template<typename T>
T resultant(poly<T> a, poly<T> b) {
if(b.is_zero()) {
return 0;
} else if(b.deg() == 0) {
return bpow(b.lead(), a.deg());
} else {
int pw = a.deg();
a %= b;
pw -= a.deg();
base mul = bpow(b.lead(), pw) * base((b.deg() & a.deg() & 1) ? -1 : 1);
base ans = resultant(b, a);
return ans * mul;
}
}

Алгоритм Half-GCD

Існує спосіб обчислити НСД та результанти за O(nlog2n)O(n \log^2 n).

Процедура, що це робить, реалізує лінійне перетворення 2×22 \times 2, яке відображає пару многочленів a(x)a(x), b(x)b(x) в іншу пару c(x),d(x)c(x), d(x) таку, що degd(x)dega(x)2\deg d(x) \leq \frac{\deg a(x)}{2}. Якщо бути достатньо акуратним, можна обчислити half-GCD будь-якої пари многочленів щонайбільше за 22 рекурсивні виклики до многочленів, які щонайменше у 22 рази менші.

Конкретні деталі алгоритму дещо втомливо пояснювати, однак ви можете знайти його реалізацію в бібліотеці як функцію half_gcd.

Після того, як half-GCD реалізовано, ви можете багаторазово застосовувати його до многочленів, доки не зведете їх до пари gcd(a,b)\gcd(a, b) та 00.

Задачі

Відеоматеріали