Блог пользователя RedLord

Автор RedLord, 11 лет назад, По-русски

Здравствуйте! При решении задач на динамику я натолкнулся на две, которые не могу решать привычным для меня подходом к ней. Во всех материалах по дп, которые я видел либо показаны готовые решения известных задач, либо разбираются самые основные его принципы, поэтому я решил написать сюда.

В первой надо найти число способов наградить k работников из n так, чтобы никакие два награжденных не стояли подряд по простому модулю. Очевидное разбиение на подзадачи d[i][j] – ответ для i работников, из которых j надо наградить. d[0][0]=d[i>0][0]=1; d[0][j>0]=0

Из k выбранных одного мы наградим первым => ответ можно разбить на независимые множества, по его номеру. Что-то вроде цикла по t от 0 до i по всем номерам. d[i][j]+=d[max(i-t-2,0)][j-1]

Проблема в том, что 1<=n,m<=10^5. Т.е. если по памяти еще можно оптимизировать, раз нам не нужны значения d[i][j-p] для вычисления d[i][j] если p>1, то по времени квадрат не проходит. Можно ли разбить на подзадачи более эффективно, или надо искать формулу?

Во второй определена функция g от последовательности чисел, которая возвращает натуральное число, равное длине максимальной подстроки из одинаковых чисел, или любой из них, если таких много. Надо найти сумму g по всем таким последовательностям, если на одной позиции могут стоять целые числа на интервале [1;c]. Само условие: http://tinyurl.com/lzkhbmn

Я написал решение за куб, который хотя бы не получает WA. Можно посмотреть здесь: http://pastebin.com/LPW2JDzH

Моя идея — найти d[pos][len].total как количество последовательностей длины pos, в которых не более len одинаковых символов стоят подряд, а d[pos][len].num не более len, и не менее len. Потом можно посчитать сумму всех d[n][j].

Пусть на позиции pos мы хотим поставить i одинаковых чисел справа. i принадлежит промежутку [1;lim]. (lim выбирается так, чтобы не превосходить len, и чтобы не создавать последовательностей длины больше n) Тогда из нулевой позиции мы можем сделать это c способами, а из ненулевой только c-1 м (Т.к. мы не можем ставить то же число, что и на позиции pos).

d[pos+i][len].num обновляется, когда мы ставим после num текущих любые числа, или когда ставим ровно len чисел.

Но из-за того, что внутри циклов достаточно дорогие операции, код падает с TL. Т.к. динамики с разными len получились независимыми, можно искать выражение d[pos][n] через d[pos-1][n], но я не представляю, как это делать.

  • Проголосовать: нравится
  • +9
  • Проголосовать: не нравится

»
11 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

В первой, кажется, можно считать динамику только для n равных степеням двойки, ну и еще помнить, взяли ли мы первого и последнего человека. Тогда можно "собрать" ответ для n, сделав O(log(n)) объединений.

  • »
    »
    11 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    А как сделать динамику для степеней двойки?

  • »
    »
    11 лет назад, # ^ |
    Rev. 3   Проголосовать: нравится 0 Проголосовать: не нравится

    Ниже привели формулу, но динамика для степеней двойки с объединением, это все равно очень интересно. Можете дать ссылку на задачи, где она используется?

    • »
      »
      »
      11 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится

      В этой задаче это все таки не подходит, тут объединение за квадрат делается. Можно конечно соптимизировать его до n log n, но такое решение скорее всего затлится.
      По поводу степеней двоек, помню только задачу L с этого контеста. На том контесте, кстати, есть еще несколько неочевидных динамик.

»
11 лет назад, # |
  Проголосовать: нравится +17 Проголосовать: не нравится

Первая решается без динамики. Есть несложная биекция между способами выбрать k из n без повторений, не выбрав два подряд, и способами выбрать k из n-k+1 без повторений. Значит, ответ Cn - k + 1k, который можно посчитать, разделив один факториал на два других по модулю (по простому модулю это особенно просто).

»
11 лет назад, # |
  Проголосовать: нравится +25 Проголосовать: не нравится

Вторая наверно решается так. Пусть g(m) — количество последовательностей длины n, в которых не встречается более m одинаковых чисел подряд. Если мы найдем все g(m), дальше все ясно. Осталось только их найти. Зафиксируем m. Пусть di — количество последовательностей длины i, в которых не встречается более m одинаковых чисел подряд. Их можно пересчитывать примерно так: (на самом деле нужно еще учесть случай j = 0 как описано в посте). Такую сумму можно находить за O(1), если иметь массив частичных сумм для d или просто двигать окно. Наверно можно даже записать проще: di = di - 1 - (c - 1)di - m - 1 + (c - 1)di - 1 (случай i < m + 1 надо тоже как-нибудь учесть).

  • »
    »
    11 лет назад, # ^ |
      Проголосовать: нравится +8 Проголосовать: не нравится

    Вроде понятно, спасибо)

    Случайно нажал случайно на минус вместо плюса. Извиянюсь.