#include #include #include #include #include #include constexpr size_t MAXN = 808; int32_t lcp[MAXN][MAXN]; int32_t ftrees[MAXN][MAXN]; void inc(int32_t i, int32_t j) { for (auto x = j + 1; x < MAXN; x += (x & -x)) { ++ftrees[i][x]; } } int32_t query(int32_t i, int32_t j) { int32_t ans = 0; for (auto x = j + 1; x > 0; x -= (x & -x)) { ans += ftrees[i][x]; } return ans; } int main() { std::string s; std::cin >> s; size_t n = s.size(); std::memset(lcp, 0, sizeof(lcp)); for (size_t i = n - 1; i < n; --i) { for (size_t j = n - 1; j < n; --j) { if (s[i] == s[j]) { lcp[i][j] = 1 + lcp[i + 1][j + 1]; } } } for (size_t i = 0; i < n; ++i) { for (size_t j = i + 1; j < n; ++j) { lcp[j][i] = lcp[i][j]; } } int64_t ans = 0; for (size_t i = 0; i < n; ++i) { for (size_t j = i + 1; j < n; ++j) { ans += std::min(j - i, lcp[i][j]); } } std::memset(ftrees, 0, sizeof(ftrees)); for (size_t len2 = n - 1; len2 > 0; --len2) { for (size_t i = 0; i < n; ++i) { for (size_t j = 0; j < n; ++j) if (lcp[i][j] == len2) { inc(i, j); } } for (size_t len1 = 1; 2 * len1 + len2 <= n; ++len1) { for (size_t i = 0, j = 2 * len1 + len2; j <= n; ++i, ++j) { if (lcp[i][j - len1] >= len1) { // add a[i][k] over all k where // k + len2 <= i if (i >= len2) { ans += query(i + len1, i - len2); } // k >= j if (j + len2 <= n) { ans += query(i + len1, n) - query(i + len1, j - 1); } } } } } std::cout << ans << '\n'; return 0; }