Поступимо за алгоритмом Флойда-Воршелла на матриці a_{ij}, щоб визначити найкоротший час заміни кожної букви на будь-яку іншу.
Складемо матрицю витрат таку, що cst[i][j]~(1 \le i \le n) містить найменшу кількість днів, за яку можна змінити букву s[i - 1] на букву .
Для зручності подальших обчислень побудуємо матрицю , що містить значення часткових сум матриці витрат за стовпцями:
Нехай dp[i][j] містить найменшу кількість днів, за яку можна перетворити перші букв рядка в рядок, що задовольняє новим вимогам Бессі, причому останні букви в новому рядку будуть буквою .
Запишемо рівняння динаміки:
Нехай перша i - 1 буква рядка вже перетворена в рядок, в якому останніми буквами стоїть буква . Тоді ми просто змінюємо букву s[i - 1] на , що можна зробити за cst[i][j] днів.
Щоб у новому рядку останніми буквами була буква , розглянемо значення dp[i - k][0], dp[i - k][1], ..., dp[i - k][m - 1]. Виберемо серед них найменше. Тобто перетворимо перші i - k букв рядка в рядок, що задовольняє новим вимогам Бессі (при цьому нам не важлива буква, якою буде закінчуватися підрядка довжини i - k, нам важливо отримати цей рядок за найменшу кількість днів). Після цього останніх букв s[i - k], s[i - k + 1], ..., , s[i - 1] початкового рядка міняємо на букву , на що піде
днів. Зазначену суму можна обчислити за константний час, використовуючи масив префіксів :
Підтримуватимемо додатковий масив , де
Таким чином, рівняння динаміки для цього випадку (i \ge k) матиме вигляд:
Залишається серед двох варіантів для dp[i][j] вибрати найменший.
Відповідь на задачу буде значення
Нам не важливо, на які саме букви закінчується нове слово Бессі.
Приклад
У даному прикладі оптимальне рішення полягає в наступному: замінити на , потім на , а після цього обидві — на . Загальна вартість змін складе 1 + 4 + 0 + 0 = 5 днів, а підсумковий рядок матиме вигляд .
За матрицею a_{ij} побудуємо матрицю витрат . Обчислимо також матрицю .
Усі значення dp[1][j]~(0 \le j \le 4) будуть рівні , оскільки довжина смуги не може бути меншою k = 2. Відповідно, mn[1] = +∞.
Розглянемо процес обчислення значень dp[2][j] (0 ≤ j ≤ 4).
dp[2][0] = ("ab" \to "aa") = cnt[''''] + cnt[''][''] = 0 + 2 = 2;
dp[2][1] = ("ab" \to "bb") = cnt[''''] + cnt[''''] = 1 + 0 = 1;
dp[2][2] = ("ab" \to "cc") = cnt[''''] + cnt[''''] = 4 + 4 = 8;
dp[2][3] = ("ab" \to "dd") = cnt[''''] + cnt[''''] = 4 + 4 = 8;
dp[2][4] = ("ab" \to "ee") = cnt[''''] + cnt[''''] = 4 + 4 = 8;
При обчисленні значень dp[3][j]~(0 \le j \le 4) рівняння
не використано, оскільки mn[1] = +∞. Тому для отримання смуг з перших букв можна лише продовжити вже побудовані смуги довжини :
dp[3][0] = dp[2][0] + cst[''''] = 2 + 5 = 7~("aaa");
dp[3][1] = dp[2][1] + cst[''''] = 1 + 5 = 6~("bbb");
dp[3][2] = dp[2][2] + cst[''''] = 8 + 0 = 8~("ccc");
dp[3][3] = dp[2][3] + cst[''''] = 8 + 3 = 11~("ddd");
dp[3][4] = dp[2][4] + cst[''''] = 8 + 2 = 10~("eee");
Значення можна отримати двома способами:
dp[4][0] = dp[3][0] + cst[''][''] = 7 + 5 = 12~("aaaa");
або
dp[4][0] = ps[4][0] - ps[2][0] + mn[2] = 12 - 2 + 1 = 11~("bbaa");
Другий випадок оптимальніший, додаються дві букви '' до рядка з двох символів. Значення mn[2] = 1 досягається на рядку "", а значить оптимальною строкою буде "".
Реалізація алгоритму
Оголосимо робочі масиви:
— мінімальна вартість перетворення букви в букву .
cst[i][j] — вартість того, щоб -я буква початкового рядка (індексація починається з ) була замінена на букву . Формально
— масив часткових сум по , щоб швидко знаходити вартість зміни підрядка довжини :
dp[i][j] — мінімальна кількість днів, щоб перетворити перші букви рядка у допустимий рядок (за правилами смуг), при цьому останні букви результату мають бути буквою .
— мінімум по всім з dp[i][j]: краще рішення для перших символів.
#define MAXN 100005
#define ALPH 26
int a[ALPH][ALPH], cst[MAXN][ALPH], ps[MAXN][ALPH], dp[MAXN][ALPH], mn[MAXN];Читаємо вхідні дані.
cin >> n >> m >> k;
cin >> s;
for (i = 0; i < m; i++)
for (j = 0; j < m; j++)
cin >> a[i][j];Запускаємо алгоритм Флойда-Воршелла на матриці . Після його завершення містить найменшу кількість днів, за яку можна змінити букву на букву .
for (x = 0; x < m; x++)
for (i = 0; i < m; i++)
for (j = 0; j < m; j++)
a[i][j] = min(a[i][j], a[i][x] + a[x][j]);У нас є m \le 26 букв. Складемо матрицю витрат таку, що cst[i][j]~(1 \le i \le n) містить найменшу кількість днів, за яку можна змінити букву s[i - 1] на букву . Індексація букв у рядку починається з .
Для зручності подальших обчислень побудуємо матрицю , що містить значення часткових сум матриці витрат за стовпцями:
for (i = 1; i <= n; i++)
for (j = 0; j < m; j++)
{
cst[i][j] = a[s[i - 1] - 'a'][j];
ps[i][j] = ps[i - 1][j] + cst[i][j];
}Ініціалізуємо масиви.
memset(dp, 0x3f, sizeof dp);
memset(mn, 0x3f, sizeof mn);
mn[0] = 0;Вичислюємо значення ячеек масиву . Букві відповідає символ s[i - 1]. Нумерація букв у змінній йде від (якій відповідає буква '') до m - 1. Інтуїтивно на кожному кроці Бессі вирішує:
або продовжувати ту ж кнопку, що й раніше,
або почати нову смугу довжиною як мінімум .
Ми обираємо те, що дешевше, і записуємо результат в dp[i][j].
Цикл по починаємо з , тому що перша допустима смуга може закінчитися лише на позиції .
for (i = k; i <= n; i++)
for (j = 0; j < m; j++)
{Продовжуємо поточну смугу. Букву початкового рядка s[i - 1] змінюємо на . Тобто:
попередні i - 1 букв вже перетворені і закінчуються на ;
тепер додаємо -ю букву s[i - 1], теж робимо її ;
вартість складе dp[i - 1][j] + cst[i][j].
dp[i][j] = min(dp[i][j], dp[i - 1][j] + cst[i][j]);Починаємо нову смугу з букв. Вважаємо, що на позиції закінчується нова смуга довжиною рівно (або більше), що складається з букви . Для цього:
Беремо краще перетворення перших (i - k) букв (все, що було раніше): mn[i - k].
Додаємо вартість заміни останніх букв (від i - k + 1 до ) на :
dp[i][j] = min(dp[i][j], ps[i][j] - ps[i - k][j] + mn[i - k]);Після обчислення всіх dp[i][j] для фіксованого , зберігаємо найкраще (мінімальне) значення серед усіх в .
mn[i] = min(mn[i], dp[i][j]);
}Виводимо відповідь.
cout << mn[n] << "\n";