You are given a string consisting of lowercase English letters. The task is to partition the string into non-empty substrings such that each substring can be rearranged to form a palindrome. Find the minimum possible number of substrings that satisfy this condition. The input is the string, and the output is the minimum possible number of substrings. For example, given the input "aabxyyzz", the output is 2, as the string can be partitioned into "aab" and "xyyzz", both of which can be rearranged to form palindromes.

# Buggy version:
from collections import defaultdict
s = input()
n = len(s)
dp = defaultdict(int)
dp[0] = 1
ls = [1<<(ord(s[0])-97)]
for i in range(1,n):
  ls.append(ls[-1]^(1<<(ord(s[i])-97)))
for i in range(n):
  for b in range(26):
    bit = 1<<b
    if dp[ls[i]^bit] == 0:
      continue
    if dp[ls[i]] == 0:
      dp[ls[i]] = dp[ls[i]^bit]+1
    else:
      dp[ls[i]] = min(dp[ls[i]^bit]+1,dp[ls[i]])
print(dp[ls[n-1]]-1)

# Fixed version:
from collections import defaultdict
s = input()
n = len(s)
dp = defaultdict(int)
dp[0] = 1
ls = [1<<(ord(s[0])-97)]
for i in range(1,n):
  ls.append(ls[-1]^(1<<(ord(s[i])-97)))
if ls[-1] == 0:
  print(1)
  exit()
for i in range(n):
  for b in range(26):
    bit = 1<<b
    if dp[ls[i]^bit] == 0:
      continue
    if dp[ls[i]] == 0:
      dp[ls[i]] = dp[ls[i]^bit]+1
    else:
      dp[ls[i]] = min(dp[ls[i]^bit]+1,dp[ls[i]])
print(dp[ls[n-1]]-1)

# Buggy version:
import math,string,itertools,fractions,heapq,collections,re,array,bisect,sys,random,time,copy,functools

sys.setrecursionlimit(10**7)
inf = 10**20
eps = 1.0 / 10**15
mod = 10**9+7

def LI(): return [int(x) for x in sys.stdin.readline().split()]
def LI_(): return [int(x)-1 for x in sys.stdin.readline().split()]
def LF(): return [float(x) for x in sys.stdin.readline().split()]
def LS(): return sys.stdin.readline().split()
def I(): return int(sys.stdin.readline())
def F(): return float(sys.stdin.readline())
def S(): return input()
def pf(s): return print(s, flush=True)


def main():
    a = [2**(ord(c)-97) for c in S()]
    b = [0]
    d = {}
    d[0] = 0
    c = 0
    ii = [2**i for i in range(26)]
    for t,i in zip(a, range(1,len(a)+1)):
        c ^= t
        tr = inf
        if c in d:
            if c == 0:
                tr = 1
            tr = b[d[c] - 1] + 1
        else:
            d[c] = i

        for j in ii:
            e = c ^ j
            if e == 0:
                tr = 1
                break
            if e in d and b[d[e]] + 1 < tr:
                tr = b[d[e]] + 1
        b.append(tr)
        if b[d[c]] > tr:
            b[d[c]] = tr
    return b[-1]



print(main())




# Fixed version:
import math,string,itertools,fractions,heapq,collections,re,array,bisect,sys,random,time,copy,functools

sys.setrecursionlimit(10**7)
inf = 10**20
eps = 1.0 / 10**15
mod = 10**9+7

def LI(): return [int(x) for x in sys.stdin.readline().split()]
def LI_(): return [int(x)-1 for x in sys.stdin.readline().split()]
def LF(): return [float(x) for x in sys.stdin.readline().split()]
def LS(): return sys.stdin.readline().split()
def I(): return int(sys.stdin.readline())
def F(): return float(sys.stdin.readline())
def S(): return input()
def pf(s): return print(s, flush=True)


def main():
    a = [2**(ord(c)-97) for c in S()]
    b = [0]
    d2 = {}
    d2[0] = 0
    c = 0
    ii = [2**i for i in range(26)]
    for t,i in zip(a, range(1,len(a)+1)):
        c ^= t
        tr = inf
        if c in d2:
            tr = d2[c] + 1

        for j in ii:
            e = c ^ j
            if e in d2 and d2[e] + 1 < tr:
                tr = d2[e] + 1
        if c not in d2 or d2[c] > tr:
            d2[c] = tr
    return d2[c] if d2[c] else 1



print(main())

# Buggy version:
s = input()
n = len(s)
cA = ord('a')
P = {0: -1}
cur = 0

dp = [10**18]*(n+1)
dp[-1] = 0

for i in range(n):
    c = ord(s[i]) - cA
    dp[i] = dp[i-1] + 1
    cur ^= 1 << c
    # even
    if cur in P:
        dp[i] = min(dp[i], P[cur] + 1)
    # odd
    for k in range(26):
        need = cur ^ (1 << k)
        if need in P:
            dp[i] = min(dp[i], P[need] + 1)
    P[cur] = min(P.get(cur, 10**18), dp[i])
print(dp[n-1])

# Fixed version:
s = input()
n = len(s)
cA = ord('a')
P = {0: 0}
cur = 0

dp = [10**18]*(n+1)
dp[-1] = 0

for i in range(n):
    c = ord(s[i]) - cA
    dp[i] = dp[i-1] + 1
    cur ^= 1 << c
    # even
    if cur in P:
        dp[i] = min(dp[i], P[cur] + 1)
    # odd
    for k in range(26):
        need = cur ^ (1 << k)
        if need in P:
            dp[i] = min(dp[i], P[need] + 1)
    P[cur] = min(P.get(cur, 10**18), dp[i])
print(dp[n-1])