// C++ program to find all distinct palindrome sub-strings
// of a given string
#include <iostream>
#include <map>
using namespace std;
// Function to print all distinct palindrome sub-strings of s
int palindromeSubStrs( string s)
{
map< string, int > m;
int n = s.size ( ) ;
// table for storing results (2 rows for odd-
// and even-length palindromes
int R[ 2 ] [ n+ 1 ] ;
// Find all sub-string palindromes from the given input
// string insert 'guards' to iterate easily over s
s = "@" + s + "#" ;
for ( int j = 0 ; j <= 1 ; j++ )
{
int rp = 0 ; // length of 'palindrome radius'
R[ j] [ 0 ] = 0 ;
int i = 1 ;
while ( i <= n)
{
// Attempt to expand palindrome centered at i
while ( s[ i - rp - 1 ] == s[ i + j + rp] )
rp++ ; // Incrementing the length of palindromic
// radius as and when we find vaid palindrome
// Assigning the found palindromic length to odd/even
// length array
R[ j] [ i] = rp;
int k = 1 ;
while ( ( R[ j] [ i - k] ! = rp - k) && ( k < rp) )
{
R[ j] [ i + k] = min( R[ j] [ i - k] ,rp - k) ;
k++ ;
}
rp = max( rp - k,0 ) ;
i + = k;
}
}
// remove 'guards'
s = s.substr ( 1 , n) ;
// Put all obtained palindromes in a hash map to
// find only distinct palindromess
m[ string( 1 , s[ 0 ] ) ] = 1 ;
for ( int i = 1 ; i <= n; i++ )
{
for ( int j = 0 ; j <= 1 ; j++ )
for ( int rp = R[ j] [ i] ; rp > 0 ; rp-- )
m[ s.substr ( i - rp - 1 , 2 * rp + j) ] = 1 ;
m[ string( 1 , s[ i] ) ] = 1 ;
}
//printing all distinct palindromes from hash map
return ( m.size ( ) - 1 ) ;
}
// Driver program
int main( ) {
ofstream fout( getenv ( "OUTPUT_PATH" ) ) ;
int res;
string _str;
getline( cin , _str) ;
res = palindromeSubStrs( _str) ;
fout << res << endl;
fout.close ( ) ;
return 0 ;
}
Ly8gQysrIHByb2dyYW0gdG8gZmluZCBhbGwgZGlzdGluY3QgcGFsaW5kcm9tZSBzdWItc3RyaW5ncwovLyBvZiBhIGdpdmVuIHN0cmluZwojaW5jbHVkZSA8aW9zdHJlYW0+CiNpbmNsdWRlIDxtYXA+CnVzaW5nIG5hbWVzcGFjZSBzdGQ7CiAKLy8gRnVuY3Rpb24gdG8gcHJpbnQgYWxsIGRpc3RpbmN0IHBhbGluZHJvbWUgc3ViLXN0cmluZ3Mgb2YgcwppbnQgcGFsaW5kcm9tZVN1YlN0cnMoc3RyaW5nIHMpCnsKICAgIG1hcDxzdHJpbmcsIGludD4gbTsKICAgIGludCBuID0gcy5zaXplKCk7CiAKICAgIC8vIHRhYmxlIGZvciBzdG9yaW5nIHJlc3VsdHMgKDIgcm93cyBmb3Igb2RkLQogICAgLy8gYW5kIGV2ZW4tbGVuZ3RoIHBhbGluZHJvbWVzCiAgICBpbnQgUlsyXVtuKzFdOwogCiAgICAvLyBGaW5kIGFsbCBzdWItc3RyaW5nIHBhbGluZHJvbWVzIGZyb20gdGhlIGdpdmVuIGlucHV0CiAgICAvLyBzdHJpbmcgaW5zZXJ0ICdndWFyZHMnIHRvIGl0ZXJhdGUgZWFzaWx5IG92ZXIgcwogICAgcyA9ICJAIiArIHMgKyAiIyI7CiAKICAgIGZvciAoaW50IGogPSAwOyBqIDw9IDE7IGorKykKICAgIHsKICAgICAgICBpbnQgcnAgPSAwOyAgIC8vIGxlbmd0aCBvZiAncGFsaW5kcm9tZSByYWRpdXMnCiAgICAgICAgUltqXVswXSA9IDA7CiAKICAgICAgICBpbnQgaSA9IDE7CiAgICAgICAgd2hpbGUgKGkgPD0gbikKICAgICAgICB7CiAgICAgICAgICAgIC8vICBBdHRlbXB0IHRvIGV4cGFuZCBwYWxpbmRyb21lIGNlbnRlcmVkIGF0IGkKICAgICAgICAgICAgd2hpbGUgKHNbaSAtIHJwIC0gMV0gPT0gc1tpICsgaiArIHJwXSkKICAgICAgICAgICAgICAgIHJwKys7ICAvLyBJbmNyZW1lbnRpbmcgdGhlIGxlbmd0aCBvZiBwYWxpbmRyb21pYwogICAgICAgICAgICAgICAgICAgICAgIC8vIHJhZGl1cyBhcyBhbmQgd2hlbiB3ZSBmaW5kIHZhaWQgcGFsaW5kcm9tZQogCiAgICAgICAgICAgIC8vIEFzc2lnbmluZyB0aGUgZm91bmQgcGFsaW5kcm9taWMgbGVuZ3RoIHRvIG9kZC9ldmVuCiAgICAgICAgICAgIC8vIGxlbmd0aCBhcnJheQogICAgICAgICAgICBSW2pdW2ldID0gcnA7CiAgICAgICAgICAgIGludCBrID0gMTsKICAgICAgICAgICAgd2hpbGUgKChSW2pdW2kgLSBrXSAhPSBycCAtIGspICYmIChrIDwgcnApKQogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICBSW2pdW2kgKyBrXSA9IG1pbihSW2pdW2kgLSBrXSxycCAtIGspOwogICAgICAgICAgICAgICAgaysrOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJwID0gbWF4KHJwIC0gaywwKTsKICAgICAgICAgICAgaSArPSBrOwogICAgICAgIH0KICAgIH0KIAogICAgLy8gcmVtb3ZlICdndWFyZHMnCiAgICBzID0gcy5zdWJzdHIoMSwgbik7CiAKICAgIC8vIFB1dCBhbGwgb2J0YWluZWQgcGFsaW5kcm9tZXMgaW4gYSBoYXNoIG1hcCB0bwogICAgLy8gZmluZCBvbmx5IGRpc3RpbmN0IHBhbGluZHJvbWVzcwogICAgbVtzdHJpbmcoMSwgc1swXSldPTE7CiAgICBmb3IgKGludCBpID0gMTsgaSA8PSBuOyBpKyspCiAgICB7CiAgICAgICAgZm9yIChpbnQgaiA9IDA7IGogPD0gMTsgaisrKQogICAgICAgICAgICBmb3IgKGludCBycCA9IFJbal1baV07IHJwID4gMDsgcnAtLSkKICAgICAgICAgICAgICAgbVtzLnN1YnN0cihpIC0gcnAgLSAxLCAyICogcnAgKyBqKV09MTsKICAgICAgICBtW3N0cmluZygxLCBzW2ldKV09MTsKICAgIH0KIAogICAgLy9wcmludGluZyBhbGwgZGlzdGluY3QgcGFsaW5kcm9tZXMgZnJvbSBoYXNoIG1hcAogICByZXR1cm4gKG0uc2l6ZSgpLTEpOwp9CiAKLy8gRHJpdmVyIHByb2dyYW0KaW50IG1haW4oKSB7CiAgICBvZnN0cmVhbSBmb3V0KGdldGVudigiT1VUUFVUX1BBVEgiKSk7CiAgICBpbnQgcmVzOwogICAgc3RyaW5nIF9zdHI7CiAgICBnZXRsaW5lKGNpbiwgX3N0cik7CiAgICAKICAgIHJlcyA9IHBhbGluZHJvbWVTdWJTdHJzKF9zdHIpOwogICAgZm91dCA8PCByZXMgPDwgZW5kbDsKICAgIAogICAgZm91dC5jbG9zZSgpOwogICAgcmV0dXJuIDA7Cn0=