/*Bismillahir Rahmanir Rahim*///{
#include <bits/stdc++.h>
#include <ext/numeric>
using namespace std; using __gnu_cxx::power;
using ll = long long; using ull = unsigned long long; using ld = long double;
const ll llinf = (1ll<<61)-1; const double eps = 1e-6, ldeps = 1e-9;
struct Dbg { static constexpr auto &os = cout;   // replace by cerr in interactive.
template<class C> static auto dud(C *x)->decltype(os << *x, 0);
template<class C> static char dud(...);
template<class C> typename enable_if<sizeof dud<C>(0)!=1,Dbg&>::type operator<<(const C &x) {os<<x; return *this;}
template<class C> Dbg &dump(C b, C e) {
    for (struct{C i;int j;} i={(*this<<"\n[",b),0}; i.i!=e and i.j<26; i.i++, i.j++) *this<<", "+2*(i.i==b)<<*i.i;
    return *this << ']';
}
template<class C> typename enable_if<sizeof dud<C>(0)==1, Dbg&>::type operator<<(const C &x) {
    return dump(begin(x), end(x));
}
template<class C, size_t X> typename enable_if<!is_same<C, const char>::value, Dbg&>::type operator<<(C (&x)[X]) {
    return dump(begin(x), end(x));
}
template<class B, class C> Dbg &operator<<(const pair<B, C> &x) {return *this<<'{'<<x.first<<", "<<x.second<<'}';}
Dbg &operator<<(ostream&(*x)(std::ostream&)) { os << x; return *this; }
} dbg;
void err(istringstream *iss) { delete iss; }
template<class C, class... Args> void err(istringstream *iss, const C &val, const Args &... args) {
    string name; *iss >> name; if (name.back()==',') name.pop_back();
    dbg << name << " = " << val << "; ", err(iss, args...);
}
#define bug(args...) dbg << __LINE__ << ": ", err(new istringstream(#args), args), dbg << endl
#define cbug(a, args...) if (a) bug(args);
#define ASSERT(a, o, b, args...) if (!((a)o(b))) bug(a, b, ##args), assert((a)o(b));
#define sl(a) int(strlen(a))
#define sz(a) int(a.size())
int T, Q, cn;//}
const int inf = 1000000007, mxn = 200005;
#define bin(m) bitset<26>(m)
#define test(m, p) (1&((m)>>(p)))
#define set_(m, p) ((m)|(1<<(p)))
#define setb(m, p) m = set_(m, p)
#define reset_(m, p) ((m)&~(1<<(p)))
#define resetb(m, p) m = reset_(m, p)
#define toggle_(m, p) ((m)^(1<<(p)))
#define toggleb(m, p) m = toggle_(m, p)
#define assign_(m, p, val) (val ? set_(m) : reset_(m))
#define assignb(m, p, val) m = assign_(m, p, val)
#define submask(s, m) s = (s-1)&m
#define getAllSet(p) ((1<<(p))-1)
#define allSet(m, p) (m) == getAllSet(p)
ll rol(ll m, int l, int w) { return ((m>>(w-l))|(m<<l))&((1<<w)-1); }

char s[mxn];
int lst[1<<26], mask[mxn];
list<pair<int, bool> > g[mxn];


// ***********************************************
// *** fill_n(lvl, mxNode+1, inf), when needed ***
// ***********************************************
int lvl[mxn];
void binaryBfs(int src) {
    deque<int> dq;
    lvl[src] = 0, dq.push_back(src);
    while (!dq.empty()) {
        int u = dq.front(), v; dq.pop_front();//bug(u, lvl[u]);
        for (auto &i : g[u]) if (v = i.first, lvl[v]>lvl[u]+i.second) {
            lvl[v] = lvl[u]+i.second;
            if (i.second) dq.push_back(v);
            else dq.push_front(v);
        }
    }
}

signed main() { cin.tie(0)->sync_with_stdio(0); cin.exceptions(cin.failbit); cout.precision(11);
/*
It's easy to see that, by maintaining mask of xor, u-v is permutation of palindrome iff
mask[u-1]==mask[v] or builtin_popcount(mask[u-1]^mask[v])==1.
At first I thought, for a certain target mask I should take as big of a chunk as possible, then it's easily possible to
do a bfs on graph. But then it turned out wrong on case like: dabbabcab, if you take dabba at once, answer will be 1+4,
instad you need to do d+abb+abcab. Unfortunately, I missed this case before getting WA.
We can't give edge to all occurences of target mask, neither can we only to last occurence. But we can give 0-weighted
edges from each occurence to next occurence and use binary bfs.
*/
    cin >> s;
    int n = sl(s), m = 0;
    memset(lst, -1, sizeof(lst)), lst[0] = 0;
    for (int i = 0; i < n; i++) {
        toggleb(m, s[i]-'a');
        if (lst[m] != -1) g[lst[m]+1].push_back({i+2, 0});
        mask[i+1] = m, lst[m] = i+1;
        for (int j = 0; j < 26; j++) {
            int o = toggle_(m, j);
            if (lst[o] != -1) g[lst[o]+1].push_back({i+2, 1});
        }
    }//bug(g);

    fill_n(lvl, n+2, inf), binaryBfs(1);
    cout << max(lvl[n+1], 1) << '\n';
}

Measured memory_bytes: 422016