Автор задачі: | Матвій Асландуков |
Задачу підготував: | Матвій Асландуков |
Розбір написав: | Матвій Асландуков |
Блок 1
Оскільки усі числа від до повинні зустрічатися у масиві рівно один раз, існує всього можливих варіантів записати числа у вершинах дерева. Усі їх можна перебрати та просто перевірити, що виконуються усі (n - 1) необхідних умов. Складність такого розв'язку — O(n \cdot n!).
Розв'язок — https://pastebin.com/M2VXx76u
Блок 2
Для розв'язання цієї групи можна було використати динамічне програмування по підмножинам. А саме, нехай dp[mask] — це кількість способів записати числа від до у вершинах дерева, номера яких присутні в масці mask. Тут позначає кількість одиничних бітів в масці . При цьому враховуються тількі ті способи, для яких виконуються усі умови для тих вершин, що вже присутні в масці.
База такої динаміки — dp[0] = 1. Для того, щоб зробити перехід, необхідно перебрати вершину , в якій буде записано значення (m + 1). Якщо для чергової вершини виконуються усі необхідні умови, необхідно зробити перехід dp[mask | (1 <.< v)] += dp[mask]. Після підрахунку усіх значень динаміки, відповіддю на задачу буде dp[(1 <.< n) - 1], що відповідає повній масці з усіми обраними вершинами. Складність такого розв'язку — O(2^n n^2) чи O(2^n n) в залежності від реалізації.
Розв'язок — https://pastebin.com/tQYcGQwG
Блок 3
Нехай sz_v — кількість вершин у піддереві вершини . Оскільки усі записані символи дорівнюють «<», то використовуючи транзитівність можна неважко довести, що значення у вершині повинно бути менше усіх значеннь вершин свого піддерева. Це означає, що значення обов'язково повинно бути записано у корені дерева. Усі інші значення від до можна незалежно розподілити по піддеревам кореня дерева. Це можна зробити cnt_v = \frac{sz_v!}{\prod_{to \in g_v} sz_{to}!} способами, де g_v — це список вершин таких, що p_{to} = v. Після того, як ми визначали які числа будуть присутніми у кожному піддереві першої вершини, можна незалежно розв'язати задачу для кожного такого піддерева. Саме тому відповідь на задачу дорівнює \prod\limits_{v=1} cnt_v. Складність такого розв'язку — чи O(n^2) в залежності від реалізації.
Розв'язок — https://pastebin.com/xsv6URJ3
Блок 4
Оскільки в даній групі усі p_i = 1, то усі некореневі вершини відрізняються між собою тільки символом c_v. Нехай — кількість ребер, на яких записано символ «>», а y = (n - 1 - x) — кількість ребер, на яких записано символ «<». Неважко побачити, що значення a_1 повинно дорівнювати (x + 1). Більш того, усі значення від до можуть бути записані в будь-якому порядку в вершинах, на ребрах до яких написаний символ «>». Аналогічно усі значення від (x + 2) до можуть бути записані в будь-якому порядку в вершинах, на ребрах до яких написаний символ «<». Тому відповідь на задачу дорівнює та може бути підрахована за .
Розв'язок — https://pastebin.com/apWgXHKH
Блок 5
У наступних двох групах для усіх вершин виконується рівність p_v = (v - 1). Це означає, що дерево являє собою звичайний масив довжиною , а символи c_v задають результат порівняння кожної пари сусідніх елементів масиву.
Спробуємо розв'язати задачу методом динамічного програмування. Нехай dp[l][r] — кількість способів розставити (r - l + 1) число на позиціях від до включно так, щоб виконувались усі необхідні відношення. База динаміки — dp[l][r] = 1 для усіх пустих підвідрізків (1 \leq l \leq n + 1, r = l - 1). Для того щоб підрахувати значення dp[l][r] для 1 \leq l \leq r \leq n, переберемо позицію i = l \ldots r, на якій буде знаходитися максимальне число серед елементів з по . Для такої позиції повинно виконуватися дві умови:
i = l або c_i = «<». Дійсно, якщо ця умова не виконується, елемент на позиції (i - 1) буде більший ніж a_i, а тому a_i не може бути максимальним числом серед елементів з по .
i = r або c_{i + 1} = «>». Дійсно, якщо ця умова не виконується, елемент на позиції (i + 1) буде більший ніж a_i, а тому a_i не може бути максимальним числом серед елементів з по .
Якщо ж ці дві умови виконуються, необхідно розподілити (r - l) чисел що залишилися на дві половини, і незалежно розв'язати дві підзадачі на менших підвідрізках. Розподілити числа на дві половини можна C_{r - l}^{i - l} способами, а тому до значення dp[l][r] необхідно додати значення C[r - l][i - l] * dp[l][i - 1] * dp[i + 1][r]. Тут C_n^k позначає кількість способів обрати предметів з . Ці значення можна підрахувати за O(n^2) за допомогою рекурентної формули C_n^k = C_{n-1}^{k-1} + C_{n-1}^{k} перед підрахунком основної динаміки. Після підрахунку усіх значень динамічного програмування, відповіддю на задачу буде значення dp[1][n].
Оскільки всього підвідрізків масиву O(n^2), та для кожного з них значення динаміки знаходиться за , загальна складність такого розв'язку — O(n^3).
Розв'язок — https://pastebin.com/d9NsgVHA
Блок 6
Спробуємо розв'язати задачу за допомогою трохи іншої динаміки. Нехай dp[r][x] (1 \leq r \leq n, 1 \leq x \leq r) — кількість способів розставити числа від до на перших елементах масиву так, щоб виконувалися усі необхідні відношення, і значення a_r дорівнювало .
База динаміки — dp[1][1] = 1. Подивимось, як можна підрахувати значення динаміки dp[r][x] при r > 1. Не обмежуючи загальності будемо вважати, що c_{r} = «<». Оскільки повинно виконуватись відношення a_{r - 1} < a_r, можемо перебрати, чому дорівнює a_{r-1} = y = 1 \ldots x - 1. Отримуємо, що dp[r][x] = \sum\limits_{y=1}^{x - 1} dp[r - 1][y].
Можна побачити, що \sum\limits_{y=1}^{x-1} dp[r - 1][y] = dp[r - 1][x - 1] + \sum\limits_{y=1}^{x-2} dp[r - 1][y] = dp[r - 1][x - 1] + dp[r][x - 1]. Використовуючи цю формулу, можна підрахувати усі значення динаміки за O(n^2). Після підрахунку усіх значень динамічного програмування, відповіддю на задачу буде \sum\limits_{i=1}^n dp[n][i].
Розв'язок — https://pastebin.com/Pw84hhBM
Блок 7
Спробуємо модифікувати розв'язок, описаний у попередньому пункті, для довільного дерева. Нехай dp[v][x] (1 \leq v \leq n, 0 \leq x < sz_v) — кількість способів розставити числа від до sz_v в усіх вершинах піддерева так, щоб виконувалися усі необхідні відношення, а також існувало рівно значень в піддереві менших за a_v (іншими словами, a_v = x + 1).
Будемо рахувати ітеративно, на кожній ітерації додаючи до вершини його чергове піддерево , та збільшуючи sz_v на sz_{to}. База динаміки — dp[v][0] = 1, sz[v] = 1. Для того щоб додати чергове піддерво та перейти у наступний шар динаміки, переберемо (0 \leq x < sz_v) — поточну кількість вершин менших за a_v та — кількість вершин у піддеріві менших за a_v. Не обмежуючи загальності будемо вважати, що c_{to} = «>». Оскільки a_v повинно бути більше ніж a_{to}, у піддереві буде хоча б одна вершина менша ніж a_v, а тому 1 \leq cnt \leq sz_{to}.
Тоді у новому шарі динаміки, кількість значень менших за a_v буде дорівнювати (x + cnt). Кількість способів розподілити ці (x + cnt) значень на вершини поточного піддерева та вершини піддерева дорівнює C_{x + cnt}^x. У свою чергу, кількість значень більших за a_v дорівнює (sz_v - 1 - x) у поточному піддереві та (sz_{to} - cnt) у піддереві вершини . Загальна кількість значень більших за a_v дорівнює (sz_v - 1 - x + sz_{to} - cnt), а тому кількість способів розподілити їх на два піддерева — C_{sz_v - 1 - x + sz_{to} - cnt}^{sz_{to} - cnt}. Оскільки a_v > a_{to} та існує рівно значень у піддереві менших за a_v, то кількість значень у піддереві менших за a_{to} повинна не перевищувати cnt - 1.
Тому можемо зробити перехід у наступний шар динаміки:
.
Суму \sum\limits_{y=0}^{cnt - 1} dp[to][y] можна знаходити за якщо підтримувати масив префіксних сум sum[v][x] = \sum\limits_{y=0}^{x} dp[v][x]. Цей масив можна дуже просто підтримувати за допомогою рекурентної формули sum[v][x] = sum[v][x - 1] + dp[v][x]. Саме тому кожен перехід динаміки можна робити за .
Спробуємо оцінити складність описаного розв'язку. Для цього необхідно оцінити сумарну кількість операцій наступного псевдокоду, де — список усіх вершин таких, що p[to] = v:
for (int v = n; v >= 1; --v) {
sz[v] = 1;
for (int to : g[v]) {
for (int x = 0; x < sz[v]; ++x) {
for (int y = 0; y < sz[to]; ++y) {
++C;
}
}
sz[v] += sz[to];
}
}Оскільки сумарний розмір усіх дорівнює (n - 1) (кількість ребер дерева), перші два цикли сумарно виконаються за . Тому загальну кількість операцій , на перший погляд, можна оцінити як O(n^3), оскільки та завжди не більші .
Але насправді можна оцінити як O(n^2). Дійсно, цикл по можна розглядити як перегляд усіх вершин з піддерева , що знаходяться лівіше піддерева . Цикл по можна розглядати як перегляд усіх вершин з піддерева . Неважко побачити, що у такому випадку кожна пара вершин буде розглядатися рівно один раз при v = lca(x, y), оскільки при всіх більш високих вершинах , вершини та вже будуть знаходитися в одному піддереві. Тут lca(x, y) позначає найменшого спільного предка вершин та . Оскільки загальна кількіста пар вершин , дорівнює \frac{n(n-1)}{2}, сумарну кількість операцій можна оцінити як O(n^2).
Розв'язок — https://pastebin.com/Za5MtZ99
Якщо написати цей розв'язок неефективно (наприклад перебирати не до поточного значення , а до загального розміру піддерева), то рішення буде працювати за O(n^3). Також за O(n^3) буде працювати рішення, що не використовує масив префіксних сум, а рахує суму окремим циклом. Саме через наявність таких рішень була зроблена сьома група тестів з обмеженнями n \leq 200.