У задачі слід розподілити задані n \cdot l літери по словам довжиною , відсортованим лексикографічно, так щоб -те слово було лексикографічно мінімально можливим.
Лексикографічний порядок слів визначається посимвольно зліва направо. Тому, щоб мінімізувати -те слово, потрібно як можна раніше (в перших позиціях) поставити до нього найменші можливі літери, не порушуючи сортування всіх слів.
Це приводить до наступного жадного алгоритму:
Відсортуємо всі літери вхідного рядка за зростанням.
Будемо будувати двовимірний масив символів
де кожен рядок — окреме слово.
Заповнюємо масив по стовпцях зліва направо, оскільки саме стовпці відповідають за позиції в словах і впливають на лексикографічний порядок.
Заповнення першого стовпця
У перший стовпець роздаємо літери тільки рядкам з номерами від до , використовуючи найменших доступних літер.
Ці літери розміщуються зверху вниз, щоб зберігався лексикографічний порядок.
Рядки з номерами k + 1, ..., n на цьому етапі не заповнюються, оскільки вони не впливають на мінімальність -го слова.
Таким чином, ми гарантуємо, що перший символ -го слова мінімальний.
Заповнення наступних стовпців
Для кожного стовпця j = 2, 3, ..., l:
Серед рядків 1, ..., k знаходимо мінімальний індекс , такий що рядки і збігаються на всіх попередніх стовпцях 1, ..., j - 1.
Це множина рядків — всі слова, які на поточному префіксі не відрізняються від -го і тому зобов'язані залишатися не більшими за нього.
У стовпці роздаємо найменші доступні літери тільки рядкам з номерами від до , зверху вниз.
Повторюємо процес, поки всі символів -го слова не будуть зафіксовані.
Заповнення інших клітинок
Після того як -те слово повністю побудовано:
Всі залишилися літери можна розподілити довільно, не порушуючи лексикографічного сортування.
Наприклад, можна послідовно заповнювати масив по рядкам зверху вниз і зліва направо залишилися літерами у відсортованому порядку.
Коректність
У кожному стовпці ми мінімізуємо поточний символ -го слова.
Ми видаємо однакові або незростаючі літери всім словам, які збігаються з ним за префіксом, тому порядок слів не порушується.
Після завершення -го слова подальші дії не можуть зробити його більшим.
Отже, отримане -те слово є лексикографічно найменшим.
Приклад
Розглянемо наступний тест
6 3 6
fgahhfgaaebdcbbebcТут потрібно скласти слів довжини , використовуючи всі літери, так щоб -те слово в лексикографічно відсортованому списку було мінімальним.
Відсортуємо рядок вхідних літер:
Всього 18 = 6 \cdot 3 літер, що відповідає розміру таблиці 6 × 3.
Стовпець 1. Заповнюємо перший стовпець літерами зверху вниз від першої до шостої рядка, оскільки саме вона нас цікавить.
Стовпець 2. Тепер розглянемо рядки, чий префікс збігається з префіксом -ї рядка. Префікс -ї рядка після першого стовпця є "". Збігатимуться будуть рядки і . Мінімальний номер такого рядка pt = 4.
У другому стовпці роздаємо мінімальні доступні літери рядкам з номерами від до .
Стовпець 3. Знову шукаємо рядки, чий префікс збігається з "" (після заповнених двох стовпців). Збігатимуться будуть рядки і . Мінімальний номер такого рядка pt = 5. Роздаємо мінімальні доступні літери рядкам з номерами від до . Тепер -те слово повністю сформовано і дорівнює "".
Заповнення залишилися літер
Після фіксації -го слова залишилися літери можна розподілити довільним коректним чином. Наприклад, заповнимо таблицю по рядкам зверху вниз і зліва направо залишилися літерами у лексикографічному порядку.
Розглянемо перший тест
3 2 2
abcdefВідсортуємо вхідний рядок літер:
Нам слід заповнити матрицю з слів по літери кожне, лексикографічно мінімізувавши при цьому -е слово.
Спочатку заповнюємо перший стовпець літерами зверху вниз, тільки для рядків з -ї по -ю, оскільки саме вони впливають на мінімальність другого слова.
Далі переходимо до другого стовпця. Його слід заповнювати, починаючи з найранішої рядка, префікс якої збігається з префіксом -ї рядка. У цьому випадку такою рядком є сама -я рядок, тому pt = 2. Заповнюємо другий стовпець літерами від рядка номер до -ї рядка.
Після цього залишилися літери розподіляємо у лексикографічному порядку по рядках зверху вниз і зліва направо, що завершує побудову коректної відповіді.
Реалізація алгоритму
Читаємо вхідні дані.
cin >> n >> l >> k;
cin >> s;Відсортуємо літери вхідного рядку. Поточною оброблюваною буквою буде .
pos = 0;
sort(s.begin(), s.end());Оголосимо матрицю результату , що складається з рядків і стовпців, де кожен рядок відповідає одному слову довжини .
vector<string> v(n, string(l, ' '));Будемо розподіляти літери по стовпцю з номером , заповнюючи рядки з номерами від до k - 1 включно (нумерація рядків починається з нуля).
int pt = 0;
for (j = 0; j < l; j++)
{
for (i = pt; i < k; i++)
v[i][j] = s[pos++];Рухаємо вказівник вперед (pt++) до тих пір, поки -ий символ (k - 1)-ої рядка не співпаде з -им символом рядку номер . В результаті вказує на рядок з найменшим номером, яка на поточному кроці збігається з префіксом рядку k - 1.
while (v[pt][j] != v[k - 1][j]) pt++;
}Після цього заповнюємо залишилися осередки матриці. Для цього послідовно проходимо по рядках зверху вниз і по стовпцях зліва направо, розподіляючи залишилися літери.
for (i = 0; i < n; i++)
for (j = 0; j < l; j++)
if (v[i][j] == ' ') v[i][j] = s[pos++];Виводимо відповідь.
for (i = 0; i < n; i++)
cout << v[i] << endl;