Palindrome
Solución
Primero, construimos el árbol palindrómico (palindromic tree) a partir de la cadena. Hay palíndromos distintos, así que nuestro árbol tendrá nodos.
Además de la información estándar sobre el palíndromo de un nodo que guardamos en él (p. ej. longitud y enlace de sufijo), guardamos la cantidad de veces que el palíndromo de cada nodo fue el sufijo máximo. Sea este número para el -ésimo nodo.
Como el palíndromo de cada nodo es una subcadena de los palíndromos de los nodos de su subárbol, la suma de en el subárbol del nodo nos da la cantidad de ocurrencias del palíndromo del nodo en la cadena.
Luego podemos hacer un DFS para hallar la cantidad de ocurrencias de cada palíndromo distinto en la cadena y después simplemente revisar cuál tiene el mayor valor de ocurrencias.
Implementación
Complejidad temporal:
Complejidad de memoria:
#include <bits/stdc++.h>
#define FOR(i, x, y) for (int i = x; i < y; i++)
typedef long long ll;
using namespace std;
struct Node {
int nxt[26], sufflink;
ll len, cnt;
vector<int> edges;
} tree[303030];
string s;
int suff, num;
ll ans = 0;
void add_letter(int pos) {
int curr = suff, curr_len = 0;
int letter = s[pos] - 'a';
while (true) {
curr_len = tree[curr].len;
if (pos - 1 - curr_len > -1 && s[pos - 1 - curr_len] == s[pos]) break;
curr = tree[curr].sufflink;
}
if (tree[curr].nxt[letter]) {
suff = tree[curr].nxt[letter];
tree[suff].cnt++;
return;
}
suff = ++num;
tree[num].len = tree[curr].len + 2;
tree[num].cnt = 1;
tree[curr].nxt[letter] = num;
if (tree[num].len == 1) {
tree[num].sufflink = 2;
tree[2].edges.push_back(num);
return;
}
while (true) {
curr = tree[curr].sufflink;
curr_len = tree[curr].len;
if (pos - 1 - curr_len > -1 && s[pos - 1 - curr_len] == s[pos]) {
tree[num].sufflink = tree[curr].nxt[letter];
tree[tree[curr].nxt[letter]].edges.push_back(num);
break;
}
}
}
void init() {
num = 2, suff = 2;
tree[1].len = -1, tree[1].sufflink = 1;
tree[2].len = 0, tree[2].sufflink = 1;
tree[1].edges.push_back(2);
}
void dfs(int node = 1) {
for (int i : tree[node].edges) {
dfs(i);
tree[node].cnt += tree[i].cnt;
}
ans = max(ans, tree[node].len * tree[node].cnt);
}
int main() {
ios_base::sync_with_stdio(0);
cin.tie(0);
cin >> s;
init();
FOR(i, 0, s.size()) add_letter(i);
dfs();
cout << ans;
return 0;
}