import sys

import numpy as np

import numba

from numba import njit, b1, i4, i8, f8



read = sys.stdin.buffer.read

readline = sys.stdin.buffer.readline

readlines = sys.stdin.buffer.readlines



MASK30 = (1 << 30) - 1

MASK31 = (1 << 31) - 1

MASK61 = (1 << 61) - 1



@njit((i8, ), cache=True)

def rh_modulo(x):

    xu, xd = x >> 61, x & MASK61

    x = xu + xd

    if x >= MASK61:

        x -= MASK61

    return x





@njit((i8, i8), cache=True)

def rh_multiply(a, b):

    au, ad = a >> 31, a & MASK31

    bu, bd = b >> 31, b & MASK31

    x = ad * bu + au * bd

    xu, xd = x >> 30, x & MASK30

    return rh_modulo(au * bu * 2 + xu + (xd << 31) + ad * bd)





@njit((i8, i8), cache=True)

def rh_pows(base, max_len):

    pows = np.empty(max_len, np.int64)

    pows[0] = 1

    for n in range(1, max_len):

        pows[n] = rh_multiply(pows[n - 1], base)

    return pows





@njit((i8[:], i8, i8[:]), cache=True)

def compute_rh(pows, base, S):

    N = len(S)

    RH = np.empty(N, np.int64)

    RH[0] = S[0] + 10

    for n in range(1, N):

        x = rh_multiply(RH[n - 1], base) + S[n] + 10

        if x >= MASK61:

            x -= MASK61

        RH[n] = x

    return RH





@njit((i8[:], i8, i8[:], i8, i8), cache=True)

def rh_substr(pows, base, RH, l, r):

    h = RH[r]

    if l > 0:

        h -= rh_multiply(RH[l], pows[r - l])

    if h < 0:

        h += MASK61

    return h



@njit((i8[:], ), cache=True)

def main(S):

    S = S.copy()

    l_ind = np.where(S == -1)[0][:-1] + 1

    r_ind = np.where(S == -1)[0][1:]

    N = len(l_ind)

    # 逆順にしておく

    for i in range(N):

        S[l_ind[i]:r_ind[i]] = S[l_ind[i]:r_ind[i]][::-1]



    # rolling hashの計算

    max_len = len(S) + 10

    base = np.random.randint(0, 1 << 31)

    base = 1000

    pows = rh_pows(base, max_len)

    RH = np.zeros_like(S)

    full_RH = np.empty(N, np.int64)

    for i in range(N):

        RH[l_ind[i]:r_ind[i]] = compute_rh(pows, base, S[l_ind[i]:r_ind[i]])

        full_RH[i] = RH[r_ind[i] - 1]

    # 後ろ（自身も含む）に置ける文字集合の計算

    sets = np.zeros_like(S)

    for i in range(N):

        for j in range(r_ind[i] - 1, l_ind[i] - 1, -1):

            sets[j] = sets[j + 1] | 1 << S[j]



    full_RH.sort()



    # 作れる組 (prefix, 右からの1文字)をすべて計算する

    ans = 0

    for i in range(N):

        for j in range(l_ind[i], r_ind[i]):

            for k in range(26):

                if sets[j] & 1 << k:

                    h = rh_multiply(RH[j - 1], base) + k + 10

                    cnt = np.searchsorted(full_RH, h, 'right')

                    cnt -= np.searchsorted(full_RH, h, 'left')

                    ans += cnt

    ans -= N

    return ans



N = int(readline())

S = np.array(list(read().rstrip()), np.int64)



S[S == ord('\n')] = -1

S[S > 0] -= ord('a')

S = np.insert(S, 0, -1)

S = np.append(S, -1)



print((main(S)))
import sys

import numpy as np

import numba

from numba import njit, b1, i4, i8, f8



read = sys.stdin.buffer.read

readline = sys.stdin.buffer.readline

readlines = sys.stdin.buffer.readlines



@njit((i8[:], ), cache=True)

def main(S):

    S = S.copy()

    l_ind = np.where(S == -1)[0][:-1] + 1

    r_ind = np.where(S == -1)[0][1:]



    # 逆順にしておく

    N = len(l_ind)

    for i in range(N):

        S[l_ind[i]:r_ind[i]] = S[l_ind[i]:r_ind[i]][::-1]



    # Trie木の構築

    path = np.zeros_like(S)

    child = np.zeros((len(S), 26), np.int64)

    is_end = np.zeros(len(S), np.bool_)



    n_node = 1

    for i in range(N):

        node = 0

        for j in range(l_ind[i], r_ind[i]):

            path[j] = node

            if child[node][S[j]] == 0:

                child[node][S[j]] = n_node

                n_node += 1

            node = child[node][S[j]]

        is_end[node] = True

    child = child[:n_node]

    is_end = is_end[:n_node]

    ans = 0

    for i in range(N):

        se = 0

        for j in range(r_ind[i] - 1, l_ind[i] - 1, -1):

            se |= 1 << S[j]

            node = path[j]

            for k in range(26):

                if se & 1 << k:

                    if is_end[child[node][k]]:

                        ans += 1

    return ans - N



N = int(readline())

S = np.array(list(read().rstrip()), np.int64)



S[S == ord('\n')] = -1

S[S > 0] -= ord('a')

S = np.insert(S, 0, -1)

S = np.append(S, -1)



print((main(S)))
import sys
import numpy as np
import numba
from numba import njit, b1, i4, i8, f8

read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines
MASK30 = (1 << 30) - 1
MASK31 = (1 << 31) - 1
MASK61 = (1 << 61) - 1


@njit((i8,), cache=True)
def rh_modulo(x):
    xu, xd = x >> 61, x & MASK61
    x = xu + xd
    if x >= MASK61:
        x -= MASK61
    return x


@njit((i8, i8), cache=True)
def rh_multiply(a, b):
    au, ad = a >> 31, a & MASK31
    bu, bd = b >> 31, b & MASK31
    x = ad * bu + au * bd
    xu, xd = x >> 30, x & MASK30
    return rh_modulo(au * bu * 2 + xu + (xd << 31) + ad * bd)


@njit((i8, i8), cache=True)
def rh_pows(base, max_len):
    pows = np.empty(max_len, np.int64)
    pows[0] = 1
    for n in range(1, max_len):
        pows[n] = rh_multiply(pows[n - 1], base)
    return pows


@njit((i8[:], i8, i8[:]), cache=True)
def compute_rh(pows, base, S):
    N = len(S)
    RH = np.empty(N, np.int64)
    RH[0] = S[0] + 10
    for n in range(1, N):
        x = rh_multiply(RH[n - 1], base) + S[n] + 10
        if x >= MASK61:
            x -= MASK61
        RH[n] = x
    return RH


@njit((i8[:], i8, i8[:], i8, i8), cache=True)
def rh_substr(pows, base, RH, l, r):
    h = RH[r]
    if l > 0:
        h -= rh_multiply(RH[l], pows[r - l])
    if h < 0:
        h += MASK61
    return h


@njit((i8[:],), cache=True)
def main(S):
    S = S.copy()
    l_ind = np.where(S == -1)[0][:-1] + 1
    r_ind = np.where(S == -1)[0][1:]
    N = len(l_ind)
    # 逆順にしておく
    for i in range(N):
        S[l_ind[i] : r_ind[i]] = S[l_ind[i] : r_ind[i]][::-1]
    # rolling hashの計算
    max_len = len(S) + 10
    base = np.random.randint(0, 1 << 31)
    base = 1000
    pows = rh_pows(base, max_len)
    RH = np.zeros_like(S)
    full_RH = np.empty(N, np.int64)
    for i in range(N):
        RH[l_ind[i] : r_ind[i]] = compute_rh(pows, base, S[l_ind[i] : r_ind[i]])
        full_RH[i] = RH[r_ind[i] - 1]
    # 後ろ（自身も含む）に置ける文字集合の計算
    sets = np.zeros_like(S)
    for i in range(N):
        for j in range(r_ind[i] - 1, l_ind[i] - 1, -1):
            sets[j] = sets[j + 1] | 1 << S[j]
    full_RH.sort()
    # 作れる組 (prefix, 右からの1文字)をすべて計算する
    ans = 0
    for i in range(N):
        for j in range(l_ind[i], r_ind[i]):
            for k in range(26):
                if sets[j] & 1 << k:
                    h = rh_multiply(RH[j - 1], base) + k + 10
                    cnt = np.searchsorted(full_RH, h, "right")
                    cnt -= np.searchsorted(full_RH, h, "left")
                    ans += cnt
    ans -= N
    return ans


N = int(readline())
S = np.array(list(read().rstrip()), np.int64)
S[S == ord("\n")] = -1
S[S > 0] -= ord("a")
S = np.insert(S, 0, -1)
S = np.append(S, -1)
print((main(S)))

import sys
import numpy as np
import numba
from numba import njit, b1, i4, i8, f8

read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines


@njit((i8[:],), cache=True)
def main(S):
    S = S.copy()
    l_ind = np.where(S == -1)[0][:-1] + 1
    r_ind = np.where(S == -1)[0][1:]
    # 逆順にしておく
    N = len(l_ind)
    for i in range(N):
        S[l_ind[i] : r_ind[i]] = S[l_ind[i] : r_ind[i]][::-1]
    # Trie木の構築
    path = np.zeros_like(S)
    child = np.zeros((len(S), 26), np.int64)
    is_end = np.zeros(len(S), np.bool_)
    n_node = 1
    for i in range(N):
        node = 0
        for j in range(l_ind[i], r_ind[i]):
            path[j] = node
            if child[node][S[j]] == 0:
                child[node][S[j]] = n_node
                n_node += 1
            node = child[node][S[j]]
        is_end[node] = True
    child = child[:n_node]
    is_end = is_end[:n_node]
    ans = 0
    for i in range(N):
        se = 0
        for j in range(r_ind[i] - 1, l_ind[i] - 1, -1):
            se |= 1 << S[j]
            node = path[j]
            for k in range(26):
                if se & 1 << k:
                    if is_end[child[node][k]]:
                        ans += 1
    return ans - N


N = int(readline())
S = np.array(list(read().rstrip()), np.int64)
S[S == ord("\n")] = -1
S[S > 0] -= ord("a")
S = np.insert(S, 0, -1)
S = np.append(S, -1)
print((main(S)))

-MASK30 = (1 << 30) - 1 -MASK31 = (1 << 31) - 1 -MASK61 = (1 << 61) - 1 - - -@njit((i8,), cache=True) -def rh_modulo(x): -    xu, xd = x >> 61, x & MASK61 -    x = xu + xd -    if x >= MASK61: -        x -= MASK61 -    return x - - -@njit((i8, i8), cache=True) -def rh_multiply(a, b): -    au, ad = a >> 31, a & MASK31 -    bu, bd = b >> 31, b & MASK31 -    x = ad * bu + au * bd -    xu, xd = x >> 30, x & MASK30 -    return rh_modulo(au * bu * 2 + xu + (xd << 31) + ad * bd) - - -@njit((i8, i8), cache=True) -def rh_pows(base, max_len): -    pows = np.empty(max_len, np.int64) -    pows[0] = 1 -    for n in range(1, max_len): -        pows[n] = rh_multiply(pows[n - 1], base) -    return pows - - -@njit((i8[:], i8, i8[:]), cache=True) -def compute_rh(pows, base, S): -    N = len(S) -    RH = np.empty(N, np.int64) -    RH[0] = S[0] + 10 -    for n in range(1, N): -        x = rh_multiply(RH[n - 1], base) + S[n] + 10 -        if x >= MASK61: -            x -= MASK61 -        RH[n] = x -    return RH - - -@njit((i8[:], i8, i8[:], i8, i8), cache=True) -def rh_substr(pows, base, RH, l, r): -    h = RH[r] -    if l > 0: -        h -= rh_multiply(RH[l], pows[r - l]) -    if h < 0: -        h += MASK61 -    return h +    # 逆順にしておく -    # 逆順にしておく -    # rolling hashの計算 -    max_len = len(S) + 10 -    base = np.random.randint(0, 1 << 31) -    base = 1000 -    pows = rh_pows(base, max_len) -    RH = np.zeros_like(S) -    full_RH = np.empty(N, np.int64) +    # Trie木の構築 +    path = np.zeros_like(S) +    child = np.zeros((len(S), 26), np.int64) +    is_end = np.zeros(len(S), np.bool_) +    n_node = 1 -        RH[l_ind[i] : r_ind[i]] = compute_rh(pows, base, S[l_ind[i] : r_ind[i]]) -        full_RH[i] = RH[r_ind[i] - 1] -    # 後ろ（自身も含む）に置ける文字集合の計算 -    sets = np.zeros_like(S) -    for i in range(N): -        for j in range(r_ind[i] - 1, l_ind[i] - 1, -1): -            sets[j] = sets[j + 1] | 1 << S[j] -    full_RH.sort() -    # 作れる組 (prefix, 右からの1文字)をすべて計算する +        node = 0 +        for j in range(l_ind[i], r_ind[i]): +            path[j] = node +            if child[node][S[j]] == 0: +                child[node][S[j]] = n_node +                n_node += 1 +            node = child[node][S[j]] +        is_end[node] = True +    child = child[:n_node] +    is_end = is_end[:n_node] -        for j in range(l_ind[i], r_ind[i]): +        se = 0 +        for j in range(r_ind[i] - 1, l_ind[i] - 1, -1): +            se |= 1 << S[j] +            node = path[j] -                if sets[j] & 1 << k: -                    h = rh_multiply(RH[j - 1], base) + k + 10 -                    cnt = np.searchsorted(full_RH, h, "right") -                    cnt -= np.searchsorted(full_RH, h, "left") -                    ans += cnt -    ans -= N -    return ans +                if se & 1 << k: +                    if is_end[child[node][k]]: +                        ans += 1 +    return ans - N