#pragma region Macros
#pragma GCC optimize("O3")
#include <bits/stdc++.h>
#define ll long long
#define rep(i,n) for(ll i=0;i<(n);i++)
#define pll pair<ll,ll>
#define pq priority_queue
#define pb push_back
#define eb emplace_back
#define fi first
#define se second
#define endl '\n'
#define ios ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0);
#define lb(c,x) distance(c.begin(),lower_bound(all(c),x))
#define ub(c,x) distance(c.begin(),upper_bound(all(c),x))

using namespace std;

template<class T> inline bool chmax(T& a,T b){if(a<b){a=b;return 1;}return 0;}
template<class T> inline bool chmin(T& a,T b){if(a>b){a=b;return 1;}return 0;}

const ll INF=1e9+7;

typedef unsigned long long ull;
#define i128 __int128_t

int popcount(ll x) { return __builtin_popcountll(x); }

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

int rnd(int n) {return uniform_int_distribution<int>(0,n-1)(rng);}
ll rndll(ll n) { return uniform_int_distribution<ll>(0,n-1)(rng);}

//mt19937,uniform_int_distribution,chronoなどは乱数生成のために用いているようです。

namespace RollingHashes {
static ull base; //乱数baseの宣言
vector<ull> p{1};
struct RollingHash {
    static constexpr ull MOD = (1uL << 61) - 1;
    vector<ull> h;
    ull mul(ull a, ull b) const {
        i128 t = (i128)(a) * (i128)(b);
        t = (t >> 61) + (t & MOD);
        if(t >= MOD) return t - MOD;
        return t;
    }
    RollingHash(const string &s) { //hash値の計算
        int sz = (int)s.size();
        if(!base) base = rnd(100000);
        h.assign(sz + 1, 0);
        p[0] = 1;
        if(sz + 1 > p.size()) {
            int psz = p.size();
            p.resize(sz + 1);
            for(int i = psz; i < sz + 1; i++) p[i] = mul(p[i - 1], base);
        }
        for(int i = 0; i < sz; i++) {
            h[i + 1] = mul(h[i], base) + s[i];
            if(h[i + 1] >= MOD) h[i + 1] -= MOD;
        }
    }
 
    ull get(int l, int r) const {
        ull res = h[r] + MOD - mul(h[l], p[r - l]);
        if(res >= MOD) return res - MOD;
        return res;
    }
 
    ull connect(ull h1, ull h2, int h2len) const {
        ull res = mul(h1, p[h2len]) + h2;
        if(res >= MOD) return res - MOD;
        return res;
    }
 
    int LCP(const RollingHash &b, int l1, int r1, int l2, int r2) {
        int len = min(r1 - l1, r2 - l2);
        int low = -1, high = len + 1;
        while(high - low > 1) {
            int mid = (low + high) / 2;
            if(get(l1, l1 + mid) == b.get(l2, l2 + mid))
                low = mid;
            else
                high = mid;
        }
        return (low);
    }
    RollingHash() = default;
};
} // namespace RollingHashes
using namespace RollingHashes;
 
int main() {
    int n;
    cin >> n;
    unordered_map<ull, int> mp;
    vector<string> s(n);
    rep(i, n){
        cin >> s[i];
        reverse(s[i].begin(),s[i].end());
    }
    
    sort(s.begin(),s.end(), [&](string &l, string &r) { return size(l) < size(r); });
    //文字列をサイズの昇順にソート
    ll ans = 0;
    rep(i, n) {
        RollingHash rh(s[i]);
        int mask = 0;
        for(int j=size(s[i]) - 1;j>=0;j--) {
            mask |= 1 << (s[i][j] - 'a');
            ans += popcount(mask & mp[rh.get(0, j)]);
        }
        mp[rh.get(0, size(s[i]) - 1)] += 1 << (s[i].back() - 'a');
    }
    cout << ans << endl;
}

Measured memory_bytes: 58448