#include <algorithm>
#include <iostream>
#include <iomanip>
#include <vector>
#include <string>
#include <limits.h>
using namespace std;
typedef long long ll;

class SegmentTree
{
public:
	SegmentTree(const vector<ll>& elements);
	void add_on_segment(int l, int r, ll delta);
	ll max_query(int l, int r);

private:
	vector<ll> tree;
	vector<ll> delayed;
	int element_cnt;
	int tree_height;
	void apply(int p, int value);
	void build(int p);
	void push(int p);
};

ll solve_dp(const string& s)
{
	int n = s.size();
	vector<vector<ll>> dp(n + 1, vector<ll>(n + 1, 0));
	for (int r = n-3; r >= 1; r--)
	{
		ll match = (s[r] == s[r + 1]) + (s[r - 1] == s[r + 2]);
		vector<ll> dp_to_right(n + 1, match);
		for (int prev_len = 2; prev_len <= n - r - 1; prev_len++)
			dp_to_right[prev_len] += dp[r + 1][prev_len];
		auto seg_tree = SegmentTree(dp_to_right);

		for (int len = 2; len <= r+1; len++)
		{
			dp[r - len + 1][len] = max(dp[r - len + 1][len], seg_tree.max_query(2, n - 1));
			if (r-len >= 0 && r + len + 1 < n && s[r - len] == s[r + len + 1])
			{
				seg_tree.add_on_segment(len + 1, n - 1, 1);
			}
		}
	}

	return *max_element(dp[0].begin(), dp[0].end());
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	
	string s; cin >> s;
	cout << solve_dp(s) << "\n";

	return 0;
}


SegmentTree::SegmentTree(const vector<ll>& elements)
{
	element_cnt = elements.size();
	delayed = vector<ll>(element_cnt);
	tree = vector<ll>(2 * element_cnt);
	copy(elements.begin(), elements.end(), tree.begin() + element_cnt);
	for (int i = element_cnt - 1; i > 0; i--)
		tree[i] = max(tree[i * 2], tree[i * 2 + 1]);
	
	int mask = 1;
	tree_height = 1;
	for (int i = 0; i < 30; i++)
	{
		if (mask & element_cnt)
		{
			tree_height = max(tree_height, i + 1);
		}
		mask <<= 1;
	}
}

void SegmentTree::add_on_segment(int l, int r, ll delta)
{
	l += element_cnt, r += element_cnt;
	int l0 = l, r0 = r;
	for (; l < r; l >>= 1, r >>= 1) {
		if (l & 1) apply(l++, delta);
		if (r & 1) apply(--r, delta);
	}
	build(l0);
	build(r0 - 1);
}

ll SegmentTree::max_query(int l, int r)
{
	l += element_cnt, r += element_cnt;
	push(l);
	push(r - 1);
	ll res = LLONG_MIN;
	for (; l < r; l >>= 1, r >>= 1) {
		if (l & 1) res = max(res, tree[l++]);
		if (r & 1) res = max(tree[--r], res);
	}
	return res;
}


void SegmentTree::apply(int p, int value) {
	tree[p] += value;
	if (p < element_cnt) delayed[p] += value;
}

void SegmentTree::build(int p) {
	while (p > 1) p >>= 1, tree[p] = max(tree[p << 1], tree[p << 1 | 1]) + delayed[p];
}

void SegmentTree::push(int p) {
	for (int s = tree_height; s > 0; --s) {
		int i = p >> s;
		if (delayed[i] != 0) {
			apply(i << 1, delayed[i]);
			apply(i << 1 | 1, delayed[i]);
			delayed[i] = 0;
		}
	}
}