Розбір
Автор задачі: | Матвій Асландуков |
Задачу підготував: | Матвій Асландуков |
Розбір написав: | Матвій Асландуков |
Блок 1
Оскільки усі числа від до повинні зустрічатися у масиві рівно один раз, існує всього можливих варіантів записати числа у вершинах дерева. Усі їх можна перебрати та просто перевірити, що виконуються усі необхідних умов. Складність такого розв'язку — .
Розв'язок — https://pastebin.com/M2VXx76u
Блок 2
Для розв'язання цієї групи можна було використати динамічне програмування по підмножинам. А саме, нехай dp[mask]
— це кількість способів записати числа від до у вершинах дерева, номера яких присутні в масці mask
. Тут позначає кількість одиничних бітів в масці . При цьому враховуються тількі ті способи, для яких виконуються усі умови для тих вершин, що вже присутні в масці.
База такої динаміки — dp[0] = 1
. Для того, щоб зробити перехід, необхідно перебрати вершину , в якій буде записано значення . Якщо для чергової вершини виконуються усі необхідні умови, необхідно зробити перехід dp[mask | (1 <.< v)] += dp[mask]
. Після підрахунку усіх значень динаміки, відповіддю на задачу буде dp[(1 <.< n) - 1]
, що відповідає повній масці з усіми обраними вершинами. Складність такого розв'язку — чи в залежності від реалізації.
Розв'язок — https://pastebin.com/tQYcGQwG
Блок 3
Нехай — кількість вершин у піддереві вершини . Оскільки усі записані символи дорівнюють «<
», то використовуючи транзитівність можна неважко довести, що значення у вершині повинно бути менше усіх значеннь вершин свого піддерева. Це означає, що значення обов'язково повинно бути записано у корені дерева. Усі інші значення від до можна незалежно розподілити по піддеревам кореня дерева. Це можна зробити способами, де — це список вершин таких, що . Після того, як ми визначали які числа будуть присутніми у кожному піддереві першої вершини, можна незалежно розв'язати задачу для кожного такого піддерева. Саме тому відповідь на задачу дорівнює . Складність такого розв'язку — чи в залежності від реалізації.
Розв'язок — https://pastebin.com/xsv6URJ3
Блок 4
Оскільки в даній групі усі , то усі некореневі вершини відрізняються між собою тільки символом . Нехай — кількість ребер, на яких записано символ «>
», а — кількість ребер, на яких записано символ «<
». Неважко побачити, що значення повинно дорівнювати . Більш того, усі значення від до можуть бути записані в будь-якому порядку в вершинах, на ребрах до яких написаний символ «>
». Аналогічно усі значення від до можуть бути записані в будь-якому порядку в вершинах, на ребрах до яких написаний символ «<
». Тому відповідь на задачу дорівнює та може бути підрахована за .
Розв'язок — https://pastebin.com/apWgXHKH
Блок 5
У наступних двох групах для усіх вершин виконується рівність . Це означає, що дерево являє собою звичайний масив довжиною , а символи задають результат порівняння кожної пари сусідніх елементів масиву.
Спробуємо розв'язати задачу методом динамічного програмування. Нехай dp[l][r]
— кількість способів розставити число на позиціях від до включно так, щоб виконувались усі необхідні відношення. База динаміки — dp[l][r] = 1
для усіх пустих підвідрізків (). Для того щоб підрахувати значення dp[l][r]
для , переберемо позицію , на якій буде знаходитися максимальне число серед елементів з по . Для такої позиції повинно виконуватися дві умови:
або «
<
». Дійсно, якщо ця умова не виконується, елемент на позиції () буде більший ніж , а тому не може бути максимальним числом серед елементів з по .або «
>
». Дійсно, якщо ця умова не виконується, елемент на позиції () буде більший ніж , а тому не може бути максимальним числом серед елементів з по .
Якщо ж ці дві умови виконуються, необхідно розподілити чисел що залишилися на дві половини, і незалежно розв'язати дві підзадачі на менших підвідрізках. Розподілити числа на дві половини можна способами, а тому до значення dp[l][r]
необхідно додати значення C[r - l][i - l] * dp[l][i - 1] * dp[i + 1][r]
. Тут позначає кількість способів обрати предметів з . Ці значення можна підрахувати за за допомогою рекурентної формули перед підрахунком основної динаміки. Після підрахунку усіх значень динамічного програмування, відповіддю на задачу буде значення dp[1][n]
.
Оскільки всього підвідрізків масиву , та для кожного з них значення динаміки знаходиться за , загальна складність такого розв'язку — .
Розв'язок — https://pastebin.com/d9NsgVHA
Блок 6
Спробуємо розв'язати задачу за допомогою трохи іншої динаміки. Нехай dp[r][x]
() — кількість способів розставити числа від до на перших елементах масиву так, щоб виконувалися усі необхідні відношення, і значення дорівнювало .
База динаміки — dp[1][1] = 1
. Подивимось, як можна підрахувати значення динаміки dp[r][x]
при . Не обмежуючи загальності будемо вважати, що «<
». Оскільки повинно виконуватись відношення , можемо перебрати, чому дорівнює . Отримуємо, що .
Можна побачити, що . Використовуючи цю формулу, можна підрахувати усі значення динаміки за . Після підрахунку усіх значень динамічного програмування, відповіддю на задачу буде .
Розв'язок — https://pastebin.com/Pw84hhBM
Блок 7
Спробуємо модифікувати розв'язок, описаний у попередньому пункті, для довільного дерева. Нехай dp[v][x]
() — кількість способів розставити числа від до в усіх вершинах піддерева так, щоб виконувалися усі необхідні відношення, а також існувало рівно значень в піддереві менших за (іншими словами, ).
Будемо рахувати ітеративно, на кожній ітерації додаючи до вершини його чергове піддерево , та збільшуючи на . База динаміки — dp[v][0] = 1, sz[v] = 1
. Для того щоб додати чергове піддерво та перейти у наступний шар динаміки, переберемо () — поточну кількість вершин менших за та — кількість вершин у піддеріві менших за . Не обмежуючи загальності будемо вважати, що «>
». Оскільки повинно бути більше ніж , у піддереві буде хоча б одна вершина менша ніж , а тому .
Тоді у новому шарі динаміки, кількість значень менших за буде дорівнювати . Кількість способів розподілити ці значень на вершини поточного піддерева та вершини піддерева дорівнює . У свою чергу, кількість значень більших за дорівнює у поточному піддереві та у піддереві вершини . Загальна кількість значень більших за дорівнює , а тому кількість способів розподілити їх на два піддерева — . Оскільки та існує рівно значень у піддереві менших за , то кількість значень у піддереві менших за повинна не перевищувати .
Тому можемо зробити перехід у наступний шар динаміки:
.
Суму можна знаходити за якщо підтримувати масив префіксних сум . Цей масив можна дуже просто підтримувати за допомогою рекурентної формули . Саме тому кожен перехід динаміки можна робити за .
Спробуємо оцінити складність описаного розв'язку. Для цього необхідно оцінити сумарну кількість операцій наступного псевдокоду, де — список усіх вершин таких, що :
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]; } }
Оскільки сумарний розмір усіх дорівнює (кількість ребер дерева), перші два цикли сумарно виконаються за . Тому загальну кількість операцій , на перший погляд, можна оцінити як , оскільки та завжди не більші .
Але насправді можна оцінити як . Дійсно, цикл по можна розглядити як перегляд усіх вершин з піддерева , що знаходяться лівіше піддерева . Цикл по можна розглядати як перегляд усіх вершин з піддерева . Неважко побачити, що у такому випадку кожна пара вершин буде розглядатися рівно один раз при , оскільки при всіх більш високих вершинах , вершини та вже будуть знаходитися в одному піддереві. Тут позначає найменшого спільного предка вершин та . Оскільки загальна кількіста пар вершин , дорівнює , сумарну кількість операцій можна оцінити як .
Розв'язок — https://pastebin.com/Za5MtZ99
Якщо написати цей розв'язок неефективно (наприклад перебирати не до поточного значення , а до загального розміру піддерева), то рішення буде працювати за . Також за буде працювати рішення, що не використовує масив префіксних сум, а рахує суму окремим циклом. Саме через наявність таких рішень була зроблена сьома група тестів з обмеженнями .