#include<bits/stdc++.h>
using u32 = uint32_t;
using i64 = int64_t;
using u64 = uint64_t;
using f64 = long double;
using i128 = __int128_t;
using f128 = __float128;
#ifndef ONLINE_JUDGE
#include "algo\debug.hpp"
#else
#define debug(...) (void)42
#endif
template<class T>
constexpr void chmax(T& x, T y) {
if (y > x) {
x = y;
}
}
template<class T>
constexpr void chmin(T& x, T y) {
if (y < x) {
x = y;
}
}
struct SAM {
static constexpr int ALPHABET_SIZE = 26;
struct Node {
int len;
int link;
std::array<int, ALPHABET_SIZE> next;
Node() : len{}, link{}, next{} {}
};
std::vector<Node> t;
SAM() {
t.assign(2, Node());
t[0].next.fill(1);
t[0].len = -1;
}
int newNode() {
t.emplace_back();
return t.size() - 1;
}
int extend(int p, int c) {
if (t[p].next[c]) {
int q = t[p].next[c];
if (t[q].len == t[p].len + 1) {
return q;
}
int r = newNode();
t[r].len = t[p].len + 1;
t[r].link = t[q].link;
t[r].next = t[q].next;
t[q].link = r;
while (t[p].next[c] == q) {
t[p].next[c] = r;
p = t[p].link;
}
return r;
}
int cur = newNode();
t[cur].len = t[p].len + 1;
while (!t[p].next[c]) {
t[p].next[c] = cur;
p = t[p].link;
}
t[cur].link = extend(p, c);
return cur;
}
int extend(int p, char c, char offset = 'a') {
return extend(p, c - offset);
}
int next(int p, int x) {
return t[p].next[x];
}
int next(int p, char c, char offset = 'a') {
return next(p, c - 'a');
}
int link(int p) {
return t[p].link;
}
int len(int p) {
return t[p].len;
}
int size() {
return t.size();
}
};
struct PAM {
static constexpr int ALPHABET_SIZE = 26;
struct Node {
int len;
int link;
int cnt;
std::array<int, ALPHABET_SIZE> next;
Node() : len{}, link{}, cnt{}, next{} {}
};
std::vector<Node> t;
int suff;
std::string s;
PAM() {
t.assign(2, Node());
t[0].len = -1;
suff = 1;
s.clear();
}
int newNode() {
t.emplace_back();
return t.size() - 1;
}
bool add(char c) {
int pos = s.size();
s += c;
int let = c - 'a';
int cur = suff, curlen = 0;
while (true) {
curlen = t[cur].len;
if (pos - 1 - curlen >= 0 && s[pos - 1 - curlen] == s[pos]) {
break;
}
cur = t[cur].link;
}
if (t[cur].next[let]) {
suff = t[cur].next[let];
return false;
}
int num = newNode();
suff = num;
t[num].len = t[cur].len + 2;
t[cur].next[let] = num;
if (t[num].len == 1) {
t[num].link = 1;
t[num].cnt = 1;
return true;
}
while (true) {
cur = t[cur].link;
curlen = t[cur].len;
if (pos - 1 - curlen >= 0 && s[pos - 1 - curlen] == s[pos]) {
t[num].link = t[cur].next[let];
break;
}
}
t[num].cnt = 1 + t[t[num].link].cnt;
return true;
}
int next(int p, int x) {
return t[p].next[x];
}
int link(int p) {
return t[p].link;
}
int len(int p) {
return t[p].len;
}
int size() {
return t.size();
}
};
auto main() ->int32_t {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout << std::fixed << std::setprecision(13);
std::string s;
std::cin >> s;
PAM pam;
std::vector<int>end;
for (const auto & c : s) {
pam.add(c);
end.push_back(pam.suff);
}
std::vector<int>f(pam.size());
for (const auto & x : end) {
f[x] += 1;
}
std::vector adj(pam.size(), std::vector<int>());
for (int i = 2; i < pam.size(); i += 1) {
adj[pam.link(i)].push_back(i);
}
i64 ans = 0;
auto dfs = [&](this auto && dfs, int x)->void{
for (const auto& y : adj[x]) {
dfs(y);
f[x] += f[y];
}
chmax(ans, i64(f[x])*pam.len(x)*pam.len(x));
};
dfs(1);
std::cout << ans << '\n';
return 0;
}