← Все вопросы

Как оценить число состояний и переходов в ДП, чтобы заранее понять, пройдёт ли по времени?

Задан 9 месяцев назад474 просмотров2 ответа
10

Часто придумываю ДП, кодирую — и ловлю TLE, потому что не прикинул заранее асимптотику. Как до написания кода аккуратно оценить сложность ДП по числу состояний и стоимости перехода, и с каким бюджетом операций сравнивать на CF (1–2 сек)?

2 ответа

14
✓ Принятый ответ — помог автору

Базовая формула: время ДП = (число состояний) × (стоимость одного перехода).

  1. Число состояний — произведение размеров всех измерений таблицы. Примеры:
    • 1D рюкзак: состояний O(nW)O(n\cdot W).
    • interval DP dp[i][j]: O(n2)O(n^2) состояний.
    • bitmask DP dp[mask][i]: O(2nn)O(2^n \cdot n).
    • digit DP dp[pos][rem][tight]: O(lenk2)O(\text{len}\cdot k\cdot 2).
  2. Стоимость перехода — сколько работы на вычисление одного состояния:
    • перебор точки разбиения в interval DP: O(n)O(n) → итого O(n3)O(n^3).
    • перебор соседа в TSP: O(n)O(n) → итого O(2nn2)O(2^n n^2).
    • константа (Фибоначчи): O(1)O(1) → итого = числу состояний.

Бюджет операций на Codeforces: ориентир 108\sim 10^810910^9 простых операций в секунду (с учётом константы, кэша). Грубо: 10810^8 — спокойно проходит за 1 сек, 10910^9 — рискованно, нужна лёгкая константа.

Пример прикидки: TSP при n=18n=182181828.51072^{18}\cdot 18^2 \approx 8.5\cdot10^7 — пройдёт. При n=22n=222109\approx 2\cdot10^9 — TLE, нужен другой подход.

7

Что ещё учитывать помимо голой формулы:

  • Память считается отдельно: число состояний × размер ячейки. 2202^{20} long long = 8 МБ — ок, 2242^{24} — уже 128 МБ, MLE. Часто память — более жёсткий лимит, чем время.
  • Константа реализации. unordered_map-мемоизация в 10–50× медленнее массива. Рекурсия добавляет накладные. Битовые операции и кэш-дружелюбный обход (по строкам) ускоряют в разы.
  • Сублинейные переходы. Иногда перебор в переходе ускоряется префиксными суммами / деревом отрезков / CHT / монотонной очередью — это снижает O(переход)O(\text{переход}) и весь ДП. Перед кодом полезно прикинуть: «а нельзя ли переход сделать за O(1)O(1)/O(log)O(\log) вместо O(n)O(n)

Правило большого пальца: ограничения в условии (n ≤ ...) намекают на целевую сложность. n20n\le 20 → ждут 2n2^n; n500n\le 500O(n3)O(n^3); n5000n\le 5000O(n2)O(n^2); n105n\le 10^5O(nlogn)O(n\log n).

Ваш ответ

Войдите, чтобы ответить на вопрос.