Neka je data niska \(S[1..n]\) koja se sastoji samo od malih slova engleske abecede. Pronaći broj palindromskih podniski dužih od jednog karaktera u niski \(S[1..n]\).
Sa standardnog ulaza se unosi niska \(S[1..n]\) (\(1 \leq n \leq 10^5\)).
Na standardni izlaz ispisati koliko ima palindromskih podniski u ovoj niski koje su duže od jednog karaktera.
aabaa
4
Naivno rešenje ovog zadatka podrazumeva da za svaku podnisku niske \(S\) proverimo da li je palindrom i prebrojimo sve podniske koje jesu palindromi. Podniski neke niske ukupno ima \(O(n^2)\). Ako za svaku u linearnom vremenu proverimo da li je palindrom, ukupna složenost algoritma je \(O(n^3)\) što je prilično neefikasno.
Mnogo efikasnije rešenje možemo dobiti primenom Manacherovog algoritma. Prvo je za svaku poziciju potrebno odrediti dužinu najdužeg palindroma čija je sredina na toj poziciji, što radimo klasičnim Manacherovim algoritmom. Nakon toga, sve što treba da uradimo je da prođemo kroz dobijeni niz i vrednost na svakoj poziciji podelimo celobrojno sa 2. Kako se svaki palindrom dobija dodavanjem po 2 karaktera na početak i kraj u odnosu na centar, deljenjem sa 2 ćemo dobiti broj palindromskih podniski čiji je centar karakter koji se razmatra. Složenost Manacherovog algoritma je linearna. Imamo još i dodatan prolazak kroz niz za šta je takođe potrebno linerano vreme, pa je i ukupna složenost \(O(n)\).
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
int manacher(const string &s)
{
const int n = s.size();
= "$";
string tmp for (int i = 0; i < n; i++) {
+= "#";
tmp += s[i];
tmp }
+= "#@";
tmp
<int> d(tmp.size());
vector
int C = 1, R = 1;
for (int i = 1; i < tmp.size() - 1; i++) {
int i_ = 2 * C - i;
if (i < R) {
[i] = min(R - i, d[i_]);
d}
while (tmp[i + (d[i] + 1)] == tmp[i - (d[i] + 1)]) {
[i]++;
d}
if (i + d[i] > R) {
= i;
C = i + d[i];
R }
}
int sum = 0;
for (int x : d) {
+= x / 2;
sum }
return sum;
}
int main ()
{
; cin >> s;
string s
<< manacher(s) << endl;
cout
return 0;
}