Быстрые операции над многочленами ч.1. (22 января 2024)
- Действия над F2 (bitset, разминка)
- Умножение за O(nm/w):
с = a << i
- Деление за O((n-m)m/w):
с[i] = 1; a = b << i
- gcd за O(nm/w) // (n+m)min(n,m) = Θ(nm)
- Умножение многочленов
- Над F2 = O(nm/w)
- Над произвольным кольцом есть O(nm) и Карацуба O(nlog2(3)) ~= n1.58
- Над комплексными числами (значит, и R, и Z) есть FFT за O(nlogn) (повторим/изучим позже)
- Упражнение: 3SUM − n чисел от -m до m, выбрать 3 с суммой 0
- Разделяй и властвуй
- Перевод из одной системы счисления в другую за logn умножений
- Деление за logn умножений : nlog2n (ссылка на будущее и nlogn)
- Деление за nlog2n: подробности
- Определение деления: хотим из A длины n и B длины n получить такой C длины n, что у A и BC совпадают n старших коэффициентов
- Основная лемма: старшие k С зависят только от старших k A и старших k B
- Деление за квадрат: cn-1 = an-1/bn-1, ci = (ai - cn-1bi - cn-2bi+1 - ...) / bn-1
- Div(A,B,k) : |A|=|B|=k
- Разделяй и властвуй: Div(A,B,n): C1 = Div(A,B,n/2), C2 = Div(A-BC1,B,n/2), return concat(C1, C2)
- Время работы T(n) = 2T(n/2) + Mul(n) = или O(nlog2n), или O(nlog2(3)) в зависимости от реализации Mul
- Разделяй и властвуй для вычисления значения многочленов в точках (evaluation) за logn делений : nlog3n
- P(x0) = P(x) mod (x - x0); Q(x) = P(x) mod (x - x1)(x - x2)...(x - xk) ⇒ Q(xi) = P(xi)
eval(P, x1, ... xk) = eval(P mod (x - x1)...(x - xk/2), x1, ... xk/2), eval(P mod (x - xk/2+1)...(x - xk), xk/2+1, ... xk)
- Время работы: T(k) = 2T(k/2) + Div(k) = O(klog2k)
- Разделяй и властвуй для интерполяции
- Ньютон: (x1...xn-1, y1...yn-1) → P(x) → P(x) + Q(x)/Q(xn)*(yn - P(xn)), где Q(x) = (x-x1)(x-x2)...(x-xn-1)
- Разделяй и властвуй: (x1...xn/2, y1...yn/2) → P(x) → P(x) + Q(x)*S(x), (x-x1)(x-x2)...(x-xn/2), а
значения S(x) в точках xn/2+1...xn вычисляются как S(xi) = (yi - P(xi)) / Q(xi)
- [skipped] Извлечение корня за logn делений
- n! mod m и факторизация целых чисел
- k = floor(sqrt(n)), рассмотрим P(x) = x(x+k)(x+2k)...(x+k(k-1))
- P(1)P(2)P(3)...P(k) = (k2)!, чтобы дополнить до n!, сделаем руками O(k) умножений, время работы: O(n1/2log2n)
- Посчитать P(x) мы можем через разделяй и властвуй за O(klog2k)
- Умножение нужно теперь делать не в C, а по модулю m. Умножим в Z (то же, что R, что C), в конце возьмём по модулю m.
- Факторизация. min d: gcd(d!, n) != 1 - минимальный делитель n. Можно бинпоиском, можно "двоичными подъёмами" за O(n1/4log2n)
- FFT (напоминание)
- Общая схема: FFT(A), FFT(B), умножить поточечно, FFT-1
- Комплексные корни из единицы: картинка, группа, умножения и степени
- Рекурсивное FFT: идея + реализация
- Тренировка понимания 1: считаем 2n − nlogn или nlog2n?
- Тренировка понимания 2: перевод между системами счисления − nlogn или nlog2n?
- Где почитать? Лекция от sankowski
Быстрые операции над многочленами ч.2. (29 января 2024)
- Разминка: число счастливых билетов из 2n цифр
- P(x) = (x0 + x1 + ... + xd)n, ответ = сумма квадратов коэффициентов P(x)
- N = dn ⇒ возведение в степень работает за O(mul(N)) = O(NlogN)
- Применения FFT
- Умножение многочленов от двух переменных xiyj (y = xn ⇒ nmlog(nm))
- Покраска в k цветов (∑I независимо xIy|I|) : предподсчитали независимые за 2n, возводим в степень k за k умножений: O(k2nn2)
- Рюкзак, subsetsum+количество: набрать ровно k предметов с суммой ровно S за O(nSlogSlogn) (разделяйка, внутри fft: T(n,S) = 2T(n/2,S) + nS*log)
- Рюкзак, subsetsum за O~(n1/2S)
- Соединяем умножения над F2 − bitset и Карацубу
- Рекурсия Карацубы, когда n ≤ w, можно умножить за n2/w = O(w), оптимизация в wlog(3)-1 раз
- Рекурсия Карацубы, при подъёме сложение и вычитания превратились в xor за O(n/w), оптимизация в w раз
- Но время Карацубы будет T(n/w)*w, где T(n) = 3T(n/2) + 1 = w(n/w)log2(3) = nlog2(3) / wlog2(3)-1
- Умножение многочленов не в C
- Над кольцом Z/mZ, m − простое вида x*2s+1, n < 2s.
- Над Z (лучше всего по КТО для разных Z/mZ)
- Быстрая нерекурсивная версия FFT
- Предподсчёт корней root[i] = (cos,sin)
- Прямой ход рекурсии − перестановка массива коэффициентов A: F[rev[i]] = A[i], rev[i] = rev[i/2]/2 + ((i%2) << (k-1))
- Обратный ход рекурсии − FOR (s=0..k-2) { n = 2s; FOR (t=0; t<N; t+=2n) FOR (j=0; j<n; j++) { tmp = ...; F[t+j+n] = ...; F[t+j] = ...; }}
- Деление многочленов за O(nlogn)
- reverse(A) = AR, заметим, что (BC)R = BRCR
- Определение деления новыми словами. A, B → C: AR = (BC)R mod xn
- Обращение ряда: получаем n первых членов обратного к A, за O(Mul(n)) AA-1 = 1 mod xn
- Получаем CR = (BR)-1AR (обращение ряда)
- Метод Ньютона и применение FFT к длинным числам
- Деление длинных чисел за O(nlogn)
- Извлечение корня за O(nlogn)