Динамика (14 ноября 2017)
- bitset: рюкзак за O(nS/w)
- НОП: оптимизация памяти
- Без восстановления ответа храним только 2 строки
- С восстановлением ответа храним только
bitset<N> f[N];
- Алгоритм Хиршберга
- Наибольшая Возрастающая Подпоследовательность
- Динамика за O(n2): len[i] → max, переход i → j
- Общее состояние процесса "идём слева направо, берём числа в ответ" : [j, len, last=a[i]]
- Динамика за O(n2): last[j,len] → min
- Замечаем свойства массива last[j]: возрастает, отличается от last[j+1] только в одной точке
- Оптимизируем до O(nlogn) динамика last[len] → min
- DP − измельчение перехода, выбор состояния, функции (на примере задачи про погрузку корабля)
- Условие: есть массив грузов (a[i]), по очереди грузятся корабли (все размера W), корабль = взять что-то слева + взять что-то справа. Погрузить всё мин числом кораблей.
- Решение #1: O(n4), k[L,R] → min, переход = перебрать префикс и суффикс
- Решение #2: O(n3), k[L,R] → min, переход = перебрать только префикс, суффикс вторым указателем
- Решение #3: O(n3), w[L,R,k] → min, переход или закончить погрузку, или взять ещё один предмет (сделали измельчение)
- Решение #4: O(n2), pair [L,R] → min, переход или закончить погрузку, или взять ещё один предмет (сделали измельчение)
- Заметим, что к решению #4 применимы оптимизации по памяти (и "хранить последние две строки" и алгоритм Хиршберга)
− Перерыв −
- DP и возведение матрицы в степень
- Пути в графе (количество путей длины ровно k)
- Числа фибоначчи
- Рекуррентные соотношения за O(k3 log n).
- Реклама: рекуррентные соотношения можно решать и за O(k log k log n)
- DP и два указателя (серверы за O(n2)) без док-ва
- Постановка задачи: разбить массив длины n на k отрезков
- Естественная динамика minCost[k,n], переход − отделить k-й отрезок, внутри перехода ставим оптимальный сервер на отрезок
- Постановка оптимального сервера на отрезок − взвешенная медиана. Можно сделать предподсчёт server[l,r]
- Также известна стоимость отрезка [l,r], она выражается через частичные суммы весов prefixSum[r+1], prefixSum[l], prefixSum[server[l,r]]
- Получили решение за O(n2k).
- Оптимизация Кнута: заменим перебор 0 ≤ p[k,n] ≤ n-1 на p[k-1,n] ≤ p[k,n] ≤ p[k,n+1]
- Разделяй и властвуй: используем p[k,n] ≤ p[k,n+1], делаем переход p[k] → p[k+1] на отрезке [l,r]: p[k,l] ≤ p[k,i] ≤ p[r,i], посчитаем за O(r-l) p[k,m], сделаем 2 рекурсивных вызова.