До заданого рядка потрібно додати мінімальну кількість символів, щоб він став паліндромом. Для цього потрібно знайти найбільший паліндром серед усіх його суфіксів, потім взяти префікс до початку цього паліндрома, розвернути його і приписати до вихідного рядка.
Наприклад, найбільшим паліндромним суфіксом рядка є . Префікс до нього — , розвертаємо його (отримуємо ) і приписуємо до вихідного рядка.
Розглянемо рядок rs = reverse(s) + s. Обчислимо для нього -функцію.
Знайдемо найменший індекс (такий, що i \ge n), для якого виконується рівність i + z_i = 2n. При цьому значення z_i буде максимальним серед таких індексів. Мінімальна кількість символів, яку необхідно дописати до вихідного рядка, щоб отримати паліндром, дорівнює n - z_i.
Для рядка "" (довжина n = 6) потрібний індекс i = 9, оскільки 9 + z_9 = 9 + 3 = 12 = 2 * 6.
Приклад
Розглянемо перший приклад. Обчислимо -функцію для рядка reverse(s) + s = "bba" + "abb" = "bbaabb".
Найменшим індексом i~(i ≥ n), для якого виконується рівність i + z_i = 2n, є i = 4. Дійсно: 4 + z_4 = 4 + 2 = 6 = 2 * 3. Тоді відповідь дорівнює n - z_i = 3 - 2 = 1. Тобто, до рядка "" достатньо додати один символ '', щоб отримати паліндром "".
Реалізація алгоритму
Функція z будує і повертає -функцію для рядка .
vector<int> zfun(string s)
{
int i, l, r, len = s.size();
vector<int> z(len, 0);
l = r = 0;
for (i = 1; i < len; i++)
{
if (i <= r) z[i] = min(r - i + 1, z[i - l]);
while (i + z[i] < len && s[z[i]] == s[i + z[i]]) z[i]++;
if (i + z[i] - 1 > r)
{
l = i;
r = i + z[i] - 1;
}
}
return z;
}Основна частина програми. Читаємо вхідний рядок .
cin >> n;
cin >> s;Будуємо рядок rs = reverse(s) + s.
rs = s;
reverse(rs.begin(), rs.end());
rs += s;Обчислюємо -функцію рядка .
z = zfun(rs);Знаходимо найменший індекс i~(i \ge n), для якого виконується рівність i + z_i = 2n. Серед усіх таких індексів значення z_i буде найбільшим.
for (i = n; i < rs.size(); i++)
if (i + z[i] == 2 * n)
{Виводимо відповідь.
cout << n - z[i] << endl;
break;
}