Problem:
Score : 600 points

Problem Statement

You are given a string S of length 2N consisting of lowercase English letters.

There are 2^{2N} ways to color each character in S red or blue. Among these ways, how many satisfy the following condition?

The string obtained by reading the characters painted red from left to right is equal to the string obtained by reading the characters painted blue from right to left.

Constraints

1 \leq N \leq 18

The length of S is 2N.

S consists of lowercase English letters.

Input

Input is given from Standard Input in the following format:

N
S

Output

Print the number of ways to paint the string that satisfy the condition.

Sample Input 1

4
cabaacba

Sample Output 1

4

There are four ways to paint the string, as follows:

cabaacba

cabaacba

cabaacba

cabaacba

Sample Input 2

11
mippiisssisssiipsspiim

Sample Output 2

504

Sample Input 3

4
abcdefgh

Sample Output 3

0

Sample Input 4

18
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

Sample Output 4

9075135300

The answer may not be representable as a 32-bit integer.

Solution in Rust (1.15.1) (judge verdict: Accepted)

pub trait Readable {
    #[doc = " Output type."]
    #[doc = ""]
    #[doc = " In most cases, `Output` should be `Self`."]
    #[doc = " This type field exists for implementing 1-origin to 0-origin conversion"]
    #[doc = " by `usize_` etc."]
    type Output;
    #[doc = " Returns how many words are read."]
    fn words_count() -> usize;
    #[doc = " Converts words into `Output`s."]
    #[doc = ""]
    #[doc = " If the conversion fails, returns `Err` with error message."]
    #[doc = ""]
    #[doc = " # Panics"]
    #[doc = ""]
    #[doc = " If `words.len()` differs from `words_count()`,"]
    #[doc = " the method may panic."]
    fn read_words(words: &[&str]) -> Result<Self::Output, String>;
}
#[macro_export]
macro_rules! readable {
    ( $ t : ty , |$ words : ident | $ read_words : expr ) => {
        readable!($t, 1, |$words| $read_words);
    };
    ( $ t : ty , $ words_count : expr , |$ words : ident | $ read_words : expr ) => {
        impl Readable for $t {
            type Output = $t;
            fn words_count() -> usize {
                $words_count
            }
            fn read_words($words: &[&str]) -> Result<$t, String> {
                Ok($read_words)
            }
        }
    };
}
readable!((), |_ss| ());
readable!(String, |ss| ss[0].to_string());
macro_rules ! impl_readable_for_ints { ( $ ( $ t : ty ) * ) => { $ ( impl Readable for $ t { type Output = Self ; fn words_count ( ) -> usize { 1 } fn read_words ( words : & [ & str ] ) -> Result <$ t , String > { use std :: str :: FromStr ; <$ t >:: from_str ( words [ 0 ] ) . map_err ( | _ | { format ! ( "cannot parse \"{}\" as {}" , words [ 0 ] , stringify ! ( $ t ) ) } ) } } ) * } ; }
impl_readable_for_ints ! ( i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 ) ;
macro_rules ! define_one_origin_int_types { ( $ new_t : ident $ int_t : ty ) => { # [ doc = " Converts 1-origin integer into 0-origin when read from stdin." ] # [ doc = "" ] # [ doc = " # Example" ] # [ doc = "" ] # [ doc = " ```no_run" ] # [ doc = " # #[macro_use] extern crate atcoder_snippets;" ] # [ doc = " # use atcoder_snippets::read::*;" ] # [ doc = " // Stdin: \"1\"" ] # [ doc = " read!(a = usize_);" ] # [ doc = " assert_eq!(a, 0);" ] # [ doc = " ```" ] # [ allow ( non_camel_case_types ) ] pub struct $ new_t ( ) ; impl Readable for $ new_t { type Output = $ int_t ; fn words_count ( ) -> usize { 1 } fn read_words ( words : & [ & str ] ) -> Result < Self :: Output , String > { <$ int_t >:: read_words ( words ) . map ( | n | n - 1 ) } } } ; ( $ new_t : ident $ int_t : ty ; $ ( $ inner_new_t : ident $ inner_int_t : ty ) ;* ) => { define_one_origin_int_types ! ( $ new_t $ int_t ) ; define_one_origin_int_types ! ( $ ( $ inner_new_t $ inner_int_t ) ;* ) ; } ; }
define_one_origin_int_types ! ( u8_ u8 ; u16_ u16 ; u32_ u32 ; u64_ u64 ; usize_ usize ) ;
macro_rules ! impl_readable_for_tuples { ( $ t : ident $ var : ident ) => ( ) ; ( $ t : ident $ var : ident ; $ ( $ inner_t : ident $ inner_var : ident ) ;* ) => { impl_readable_for_tuples ! ( $ ( $ inner_t $ inner_var ) ;* ) ; impl <$ t : Readable , $ ( $ inner_t : Readable ) ,*> Readable for ( $ t , $ ( $ inner_t ) ,* ) { type Output = ( <$ t >:: Output , $ ( <$ inner_t >:: Output ) ,* ) ; fn words_count ( ) -> usize { let mut n = <$ t >:: words_count ( ) ; $ ( n += <$ inner_t >:: words_count ( ) ; ) * n } # [ allow ( unused_assignments ) ] fn read_words ( words : & [ & str ] ) -> Result < Self :: Output , String > { let mut start = 0 ; let $ var = <$ t >:: read_words ( & words [ start .. start +<$ t >:: words_count ( ) ] ) ?; start += <$ t >:: words_count ( ) ; $ ( let $ inner_var = <$ inner_t >:: read_words ( & words [ start .. start +<$ inner_t >:: words_count ( ) ] ) ?; start += <$ inner_t >:: words_count ( ) ; ) * Ok ( ( $ var , $ ( $ inner_var ) ,* ) ) } } } ; }
impl_readable_for_tuples ! ( T4 x4 ; T3 x3 ; T2 x2 ; T1 x1 ) ;
pub trait ReadableFromLine {
    type Output;
    fn read_line(line: &str) -> Result<Self::Output, String>;
}
fn split_into_words(line: &str) -> Vec<&str> {
    #[allow(deprecated)]
    line.trim_right_matches('\n').split_whitespace().collect()
}
impl<T: Readable> ReadableFromLine for T {
    type Output = T::Output;
    fn read_line(line: &str) -> Result<T::Output, String> {
        let words = split_into_words(line);
        if words.len() != T::words_count() {
            return Err(format!(
                "line \"{}\" has {} words, expected {}",
                line,
                words.len(),
                T::words_count()
            ));
        }
        T::read_words(&words)
    }
}
impl<T: Readable> ReadableFromLine for Vec<T> {
    type Output = Vec<T::Output>;
    fn read_line(line: &str) -> Result<Self::Output, String> {
        let n = T::words_count();
        let words = split_into_words(line);
        if words.len() % n != 0 {
            return Err(format!(
                "line \"{}\" has {} words, expected multiple of {}",
                line,
                words.len(),
                n
            ));
        }
        let mut result = Vec::new();
        for chunk in words.chunks(n) {
            match T::read_words(chunk) {
                Ok(v) => result.push(v),
                Err(msg) => {
                    let flagment_msg = if n == 1 {
                        format!("word {}", result.len())
                    } else {
                        let l = result.len();
                        format!("words {}-{}", n * l + 1, (n + 1) * l)
                    };
                    return Err(format!("{} of line \"{}\": {}", flagment_msg, line, msg));
                }
            }
        }
        Ok(result)
    }
}
impl<T: Readable, U: Readable> ReadableFromLine for (T, Vec<U>) {
    type Output = (T::Output, <Vec<U> as ReadableFromLine>::Output);
    fn read_line(line: &str) -> Result<Self::Output, String> {
        let n = T::words_count();
        #[allow(deprecated)]
        let trimmed = line.trim_right_matches('\n');
        let words_and_rest: Vec<&str> = trimmed.splitn(n + 1, ' ').collect();
        if words_and_rest.len() < n {
            return Err(format!(
                "line \"{}\" has {} words, expected at least {}",
                line,
                words_and_rest.len(),
                n
            ));
        }
        let words = &words_and_rest[..n];
        let empty_str = "";
        let rest = words_and_rest.get(n).unwrap_or(&empty_str);
        Ok((T::read_words(words)?, Vec::<U>::read_line(rest)?))
    }
}
macro_rules ! impl_readable_from_line_for_tuples_with_vec { ( $ t : ident $ var : ident ) => ( ) ; ( $ t : ident $ var : ident ; $ ( $ inner_t : ident $ inner_var : ident ) ;+ ) => { impl_readable_from_line_for_tuples_with_vec ! ( $ ( $ inner_t $ inner_var ) ;+ ) ; impl <$ t : Readable , $ ( $ inner_t : Readable ) ,+ , U : Readable > ReadableFromLine for ( $ t , $ ( $ inner_t ) ,+ , Vec < U > ) { type Output = ( $ t :: Output , $ ( $ inner_t :: Output ) ,+ , Vec < U :: Output > ) ; fn read_line ( line : & str ) -> Result < Self :: Output , String > { let mut n = $ t :: words_count ( ) ; $ ( n += $ inner_t :: words_count ( ) ; ) + # [ allow ( deprecated ) ] let trimmed = line . trim_right_matches ( '\n' ) ; let words_and_rest : Vec <& str > = trimmed . splitn ( n + 1 , ' ' ) . collect ( ) ; if words_and_rest . len ( ) < n { return Err ( format ! ( "line \"{}\" has {} words, expected at least {}" , line , words_and_rest . len ( ) , n ) ) ; } let words = & words_and_rest [ .. n ] ; let empty_str = "" ; let rest = words_and_rest . get ( n ) . unwrap_or ( & empty_str ) ; let ( $ var , $ ( $ inner_var ) ,* ) = < ( $ t , $ ( $ inner_t ) ,+ ) >:: read_words ( words ) ?; Ok ( ( $ var , $ ( $ inner_var ) ,* , Vec ::< U >:: read_line ( rest ) ? ) ) } } } ; }
impl_readable_from_line_for_tuples_with_vec ! ( T4 t4 ; T3 t3 ; T2 t2 ; T1 t1 ) ;
pub fn read<T: ReadableFromLine>() -> T::Output {
    let mut line = String::new();
    std::io::stdin().read_line(&mut line).unwrap();
    T::read_line(&line).unwrap()
}
#[macro_export]
macro_rules ! read { ( ) => { let mut line = String :: new ( ) ; std :: io :: stdin ( ) . read_line ( & mut line ) . unwrap ( ) ; } ; ( $ pat : pat = $ t : ty ) => { let $ pat = read ::<$ t > ( ) ; } ; ( $ ( $ pat : pat = $ t : ty ) ,+ ) => { read ! ( ( $ ( $ pat ) ,* ) = ( $ ( $ t ) ,* ) ) ; } ; }
#[macro_export]
macro_rules ! readls { ( $ ( $ pat : pat = $ t : ty ) ,+ ) => { $ ( read ! ( $ pat = $ t ) ; ) * } ; }
pub fn readx<T: ReadableFromLine>() -> Vec<T::Output> {
    use std::io::{self, BufRead};
    let stdin = io::stdin();
    let result = stdin
        .lock()
        .lines()
        .map(|line_result| {
            let line = line_result.expect("read from stdin failed");
            T::read_line(&line).unwrap()
        }).collect();
    result
}
#[macro_export]
macro_rules ! readx_loop { ( |$ pat : pat = $ t : ty | $ body : expr ) => { use std :: io :: BufRead ; let stdin = std :: io :: stdin ( ) ; for line in stdin . lock ( ) . lines ( ) { let line = line . expect ( "read from stdin failed" ) ; let $ pat = <$ t >:: read_line ( & line ) . unwrap ( ) ; $ body } } ; ( |$ ( $ pat : pat = $ t : ty ) ,*| $ body : expr ) => { readx_loop ! ( | ( $ ( $ pat ) ,* ) = ( $ ( $ t ) ,* ) | $ body ) ; } ; }
pub fn readn<T: ReadableFromLine>(n: usize) -> Vec<T::Output> {
    use std::io::{self, BufRead};
    let stdin = io::stdin();
    let result: Vec<T::Output> = stdin
        .lock()
        .lines()
        .take(n)
        .map(|line_result| {
            let line = line_result.expect("read from stdin failed");
            T::read_line(&line).unwrap()
        }).collect();
    if result.len() < n {
        panic!(
            "expected reading {} lines, but only {} lines are read",
            n,
            result.len()
        );
    }
    result
}
#[macro_export]
macro_rules ! readn_loop { ( $ n : expr , |$ pat : pat = $ t : ty | $ body : expr ) => { use std :: io :: BufRead ; let stdin = std :: io :: stdin ( ) ; { let mut lock = stdin . lock ( ) ; for _ in 0 ..$ n { let mut line = String :: new ( ) ; lock . read_line ( & mut line ) . expect ( "read from stdin failed" ) ; let $ pat = <$ t >:: read_line ( & line ) . unwrap ( ) ; $ body } } } ; ( $ n : expr , |$ ( $ pat : pat = $ t : ty ) ,*| $ body : expr ) => { readn_loop ! ( $ n , | ( $ ( $ pat ) ,* ) = ( $ ( $ t ) ,* ) | $ body ) ; } ; }
pub trait Words {
    fn read<T: Readable>(&self) -> T::Output;
}
impl<'a> Words for [&'a str] {
    fn read<T: Readable>(&self) -> T::Output {
        T::read_words(self).unwrap()
    }
}
impl<'a> Words for &'a str {
    fn read<T: Readable>(&self) -> T::Output {
        T::read_words(&[self]).unwrap()
    }
}

#[derive(Clone, PartialEq, Eq)]
pub enum ListInner<T: Clone> {
    Nil,
    Cons(T, List<T>),
}
pub use self::ListInner::{Cons, Nil};
#[derive(Clone, PartialEq, Eq)]
pub struct List<T: Clone> {
    inner: std::rc::Rc<ListInner<T>>,
    len: usize,
}
impl<T: Clone> List<T> {
    pub fn nil() -> List<T> {
        List {
            inner: std::rc::Rc::new(Nil),
            len: 0,
        }
    }
    #[doc = " Whether the list is nil."]
    pub fn is_nil(&self) -> bool {
        match self.as_ref() {
            &Nil => true,
            &Cons(_, _) => false,
        }
    }
    #[doc = " Length of the list."]
    #[doc = ""]
    #[doc = " `len()` is O(1) time because each sublist holds its length."]
    pub fn len(&self) -> usize {
        self.len
    }
    #[doc = " Extract head of non-empty list."]
    #[doc = ""]
    #[doc = " # Panic"]
    #[doc = ""]
    #[doc = " Panics if `self` is nil."]
    #[doc = ""]
    #[doc = " # Example"]
    #[doc = ""]
    #[doc = " ```"]
    #[doc = " # #[macro_use] extern crate atcoder_snippets;"]
    #[doc = " # use atcoder_snippets::collections::list::*;"]
    #[doc = " assert_eq!(list![1, 2, 3].head(), 1);"]
    #[doc = " ```"]
    pub fn head(&self) -> T {
        match self.as_ref() {
            &Nil => panic!("cannot find head of nil"),
            &Cons(ref head, _) => head.clone(),
        }
    }
    #[doc = " Extract tail of non-empty list."]
    #[doc = ""]
    #[doc = " # Panic"]
    #[doc = ""]
    #[doc = " Panics if `self` is nil."]
    #[doc = ""]
    #[doc = " # Example"]
    #[doc = ""]
    #[doc = " ```"]
    #[doc = " # #[macro_use] extern crate atcoder_snippets;"]
    #[doc = " # use atcoder_snippets::collections::list::*;"]
    #[doc = " assert_eq!(list![1, 2, 3].tail(), list![2, 3]);"]
    #[doc = " ```"]
    pub fn tail(&self) -> List<T> {
        match self.as_ref() {
            &Nil => panic!("cannot find head of nil"),
            &Cons(_, ref tail) => tail.clone(),
        }
    }
    #[doc = " Gets an iterator without moving `self`."]
    pub fn iter(&self) -> List<T> {
        self.clone()
    }
    #[doc = " Concatenates two lists."]
    pub fn append(&self, other: &List<T>) -> List<T> {
        append_tailrec(self, other, List::nil())
    }
    #[doc = " Reverses `self`, then concatenates two lists."]
    pub fn rev_append(&self, other: &List<T>) -> List<T> {
        match self.as_ref() {
            &Nil => other.clone(),
            &Cons(ref head, ref tail) => tail.rev_append(&head.clone().cons(other)),
        }
    }
    #[cfg(test)]
    fn take(self) -> std::rc::Rc<ListInner<T>> {
        self.inner
    }
}
fn append_tailrec<T: Clone>(list1: &List<T>, list2: &List<T>, list1_rev: List<T>) -> List<T> {
    match list1.as_ref() {
        &Nil => list1_rev.rev_append(list2),
        &Cons(ref head, ref tail) => append_tailrec(tail, list2, head.clone().cons(list1_rev)),
    }
}
impl<T: Clone> AsRef<ListInner<T>> for List<T> {
    fn as_ref(&self) -> &ListInner<T> {
        self.inner.as_ref()
    }
}
impl<T: Clone + std::fmt::Debug> std::fmt::Debug for List<T> {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self.inner.as_ref() {
            &Nil => write!(f, "nil"),
            &Cons(ref head, ref tail) => write!(f, "{:?} :: {:?}", head, tail),
        }
    }
}
impl<T: Clone + PartialOrd> PartialOrd for List<T> {
    fn partial_cmp(&self, other: &List<T>) -> Option<std::cmp::Ordering> {
        use std::cmp::Ordering::*;
        match (self.as_ref(), other.as_ref()) {
            (&Nil, &Nil) => Some(Equal),
            (&Nil, &Cons(_, _)) => Some(Less),
            (&Cons(_, _), &Nil) => Some(Greater),
            (&Cons(ref head1, ref tail1), &Cons(ref head2, ref tail2)) => head1
                .partial_cmp(&head2)
                .and_then(|ordering| match ordering {
                    Equal => tail1.partial_cmp(tail2),
                    _ => Some(ordering),
                }),
        }
    }
}
impl<T: Clone + Ord> Ord for List<T> {
    fn cmp(&self, other: &List<T>) -> std::cmp::Ordering {
        use std::cmp::Ordering::*;
        match (self.as_ref(), other.as_ref()) {
            (&Nil, &Nil) => Equal,
            (&Nil, &Cons(_, _)) => Less,
            (&Cons(_, _), &Nil) => Greater,
            (&Cons(ref head1, ref tail1), &Cons(ref head2, ref tail2)) => match head1.cmp(&head2) {
                Equal => tail1.cmp(tail2),
                determined => determined,
            },
        }
    }
}
impl<T: Clone> Iterator for List<T> {
    type Item = T;
    fn next(&mut self) -> Option<T> {
        let cons;
        match self.as_ref() {
            &Nil => return None,
            &Cons(ref head, ref tail) => cons = (head.clone(), tail.clone()),
        }
        *self = cons.1;
        Some(cons.0)
    }
}
impl<'a, T: Clone> IntoIterator for &'a List<T> {
    type Item = T;
    type IntoIter = List<T>;
    fn into_iter(self) -> List<T> {
        self.iter()
    }
}
impl<T: Clone> std::iter::FromIterator<T> for List<T> {
    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> List<T> {
        let xs: Vec<T> = iter.into_iter().collect();
        let mut list = List::nil();
        for x in xs.into_iter().rev() {
            list = x.cons(list);
        }
        list
    }
}
pub trait IntoCons<T: Clone, L: std::borrow::Borrow<List<T>>> {
    fn cons(self, tail: L) -> List<T>;
}
impl<T: Clone, L: std::borrow::Borrow<List<T>>> IntoCons<T, L> for T {
    fn cons(self, tail: L) -> List<T> {
        let tail_cloned: List<T> = tail.borrow().clone().into();
        let tail_len = tail_cloned.len;
        List {
            inner: std::rc::Rc::new(Cons(self, tail_cloned)),
            len: tail_len + 1,
        }
    }
}
#[macro_export]
macro_rules ! list { [ ] => { List :: nil ( ) } ; [ $ head : expr ] => { $ head . cons ( List :: nil ( ) ) } ; [ $ head : expr , $ ( $ tail : expr ) ,* ] => { $ head . cons ( list ! [ $ ( $ tail ) ,* ] ) } ; [ $ head : expr , $ ( $ tail : expr ) ,+ , ] => { list ! [ $ head , $ ( $ tail ) ,* ] } ; }

#[derive(Clone)]
pub struct StepBy<I> {
    iter: I,
    step: usize,
    first_take: bool,
}
impl<I: Iterator> Iterator for StepBy<I> {
    type Item = I::Item;
    fn next(&mut self) -> Option<Self::Item> {
        if self.first_take {
            self.first_take = false;
            self.iter.next()
        } else {
            self.iter.nth(self.step)
        }
    }
}
#[derive(Clone)]
pub struct LScan<I: Iterator, S: Clone, F: FnMut(&S, I::Item) -> S> {
    iter: I,
    state: Option<S>,
    f: F,
}
impl<I: Iterator, S: Clone, F> Iterator for LScan<I, S, F>
where
    F: FnMut(&S, I::Item) -> S,
{
    type Item = S;
    fn next(&mut self) -> Option<S> {
        if self.state.is_none() {
            return None;
        }
        let state_inner = self.state.take().unwrap();
        if let Some(item) = self.iter.next() {
            self.state = Some((self.f)(&state_inner, item));
        }
        Some(state_inner)
    }
}
pub struct Flatten<I: Iterator>
where
    I::Item: IntoIterator,
{
    outer_iter: I,
    inner_iter: Option<<<I as Iterator>::Item as IntoIterator>::IntoIter>,
}
impl<I, J> Iterator for Flatten<I>
where
    I: Iterator<Item = J>,
    J: IntoIterator,
{
    type Item = <<J as IntoIterator>::IntoIter as Iterator>::Item;
    fn next(&mut self) -> Option<J::Item> {
        loop {
            if let Some(inner_iter) = self.inner_iter.as_mut() {
                if let item @ Some(_) = inner_iter.next() {
                    return item;
                }
            }
            match self.outer_iter.next() {
                None => return None,
                Some(inner) => self.inner_iter = Some(inner.into_iter()),
            }
        }
    }
}
pub struct GroupBy<K: Eq, I: Iterator, F: FnMut(&I::Item) -> K> {
    cur: Option<(I::Item, K)>,
    iter: I,
    key_fn: F,
}
impl<K: Eq, I: Iterator, F: FnMut(&I::Item) -> K> Iterator for GroupBy<K, I, F> {
    type Item = Vec<I::Item>;
    fn next(&mut self) -> Option<Vec<I::Item>> {
        let cur = self.cur.take();
        cur.map(|(item, key)| {
            let mut group = vec![item];
            loop {
                let next = self.iter.next();
                match next {
                    Some(next_item) => {
                        let next_key = (self.key_fn)(&next_item);
                        if key == next_key {
                            group.push(next_item);
                        } else {
                            self.cur = Some((next_item, next_key));
                            break;
                        }
                    }
                    None => {
                        self.cur = None;
                        break;
                    }
                }
            }
            group
        })
    }
}
use std::fmt;
pub trait RichIterator: Iterator {
    fn step_by_(self, step: usize) -> StepBy<Self>
    where
        Self: Sized,
    {
        assert_ne!(step, 0);
        StepBy {
            iter: self,
            step: step - 1,
            first_take: true,
        }
    }
    fn for_each<F: FnMut(Self::Item)>(self, mut f: F)
    where
        Self: Sized,
    {
        for item in self {
            f(item);
        }
    }
    fn lscan<S: Clone, F>(self, state: S, f: F) -> LScan<Self, S, F>
    where
        Self: Sized,
        F: FnMut(&S, Self::Item) -> S,
    {
        LScan {
            iter: self,
            state: Some(state),
            f: f,
        }
    }
    fn get_unique(mut self) -> Option<Self::Item>
    where
        Self: Sized,
        Self::Item: Eq,
    {
        let first_opt = self.next();
        first_opt.and_then(|first| {
            if self.all(|item| item == first) {
                Some(first)
            } else {
                None
            }
        })
    }
    fn flatten(mut self) -> Flatten<Self>
    where
        Self: Sized,
        Self::Item: IntoIterator,
    {
        let inner_opt = self.next();
        Flatten {
            outer_iter: self,
            inner_iter: inner_opt.map(|inner| inner.into_iter()),
        }
    }
    #[doc = " `f`\u{306b}\u{3088}\u{3063}\u{3066}\u{30b0}\u{30eb}\u{30fc}\u{30d7}\u{5206}\u{3051}\u{3055}\u{308c}\u{305f}`Vec`\u{3092}\u{751f}\u{6210}\u{3059}\u{308b}\u{30a4}\u{30c6}\u{30ec}\u{30fc}\u{30bf}\u{3092}\u{8fd4}\u{3059}"]
        #[doc = ""]
        #[doc = " SQL\u{306e}group_by\u{3067}\u{306f}\u{306a}\u{304f}\u{3001}Python\u{306e}itertool\u{3084}Rust\u{306e}itertool\u{3068}\u{540c}\u{3058}\u{610f}\u{5473}\u{8ad6}\u{3067}\u{3042}\u{308b}"]
    fn group_by<K: Eq, F: FnMut(&Self::Item) -> K>(mut self, mut f: F) -> GroupBy<K, Self, F>
    where
        Self: Sized,
    {
        let next = self.next();
        GroupBy {
            cur: next.map(|item| {
                let key = f(&item);
                (item, key)
            }),
            iter: self,
            key_fn: f,
        }
    }
    fn join(mut self, sep: &str) -> String
    where
        Self: Sized,
        Self::Item: fmt::Display,
    {
        let mut result = String::new();
        if let Some(first) = self.next() {
            result.push_str(&format!("{}", first));
        }
        for s in self {
            result.push_str(&format!("{}{}", sep, s));
        }
        result
    }
    fn cat(self) -> String
    where
        Self: Sized,
        Self::Item: fmt::Display,
    {
        self.join("")
    }
}
impl<I: Iterator> RichIterator for I {}
pub struct Unfold<T, F>
where
    F: FnMut(&T) -> Option<T>,
{
    state: Option<T>,
    f: F,
}
impl<T, F> Iterator for Unfold<T, F>
where
    F: FnMut(&T) -> Option<T>,
{
    type Item = T;
    fn next(&mut self) -> Option<T> {
        if self.state.is_none() {
            return None;
        }
        let state_inner = self.state.take().unwrap();
        self.state = (self.f)(&state_inner);
        Some(state_inner)
    }
}
pub fn unfold<T, F>(init: T, f: F) -> Unfold<T, F>
where
    F: FnMut(&T) -> Option<T>,
{
    Unfold {
        state: Some(init),
        f: f,
    }
}
pub struct Iterate<T, F>
where
    F: FnMut(&T) -> T,
{
    state: T,
    f: F,
}
impl<T, F> Iterator for Iterate<T, F>
where
    F: FnMut(&T) -> T,
{
    type Item = T;
    fn next(&mut self) -> Option<T> {
        use std::mem::swap;
        let mut state = (self.f)(&self.state);
        swap(&mut state, &mut self.state);
        Some(state)
    }
}
pub fn iterate<T, F>(init: T, f: F) -> Iterate<T, F>
where
    F: FnMut(&T) -> T,
{
    Iterate { state: init, f: f }
}

use std::collections::HashMap;

fn split(mut r: Vec<u8>, mut b: Vec<u8>, rest: &[u8],
         map: &mut HashMap<(Vec<u8>, Vec<u8>), usize>) {
    match rest.split_first() {
        None => {
            r.reverse();
            b.reverse();
            let mut count = map.entry((b, r)).or_insert(0);
            *count += 1;
        },
        Some((&hd, tl)) => {
            let mut next_r = r.clone();
            next_r.push(hd);
            let mut next_b = b.clone();
            next_b.push(hd);
            split(next_r, b, tl, map);
            split(r, next_b, tl, map);
        }
    }
}

fn count(r: Vec<u8>, b: Vec<u8>, rest: &[u8],
         map: &HashMap<(Vec<u8>, Vec<u8>), usize>) -> usize {
    match rest.split_first() {
        None => map.get(&(r, b)).cloned().unwrap_or(0),
        Some((&hd, tl)) => {
            let mut next_r = r.clone();
            next_r.push(hd);
            let mut next_b = b.clone();
            next_b.push(hd);
            count(next_r, b, tl, map) + count(r, next_b, tl, map)
        }
    }
}

fn main() {
    read!();
    read!(s = String);
    let (left, right) = s.as_bytes().split_at(s.len()/2);

    let mut map = HashMap::new();
    split(Vec::new(), Vec::new(), &left, &mut map);
    println!("{}", count(Vec::new(), Vec::new(), &right, &map));
}