#include <bits/stdc++.h>
using namespace std;
#define TRACE(x) 
#define WATCH(x) TRACE( cout << #x" = " << x << endl)
#define PRINT(x) TRACE(printf(x))
#define WATCHR(a, b) TRACE( for(auto c = a; c != b;) cout << *(c++) << " "; cout << endl)
#define WATCHC(V) TRACE({cout << #V" = "; WATCHR(V.begin(), V.end());})
#define rep(i, a, b) for(int i = (a); (i) < (b); ++(i))
#define trav(a, x) for(auto& a : x)
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define sz(x) static_cast<int>(x.size())
#define mp make_pair
#define fi first
#define se second

using vi = vector<int>;
using vvi = vector<vi>;
using ll = long long;
using vll = vector<ll>;
using pii = pair<int, int>;
using pll = pair<ll, ll>;

void buff() { ios::sync_with_stdio(false); cin.tie(nullptr); }

template<typename T> inline void remin(T& x, const T& y) { x = min(x, y); }
template<typename T> inline void remax(T& x, const T& y) { x = max(x, y); }

template<typename T> ostream& operator<<(ostream &os, const vector<T>& v) {
  os << "{"; string sep; for(const auto& x : v) os << sep << x, sep = ", "; return os << "}"; 
}

template<typename T, size_t size> ostream& operator<<(ostream& os, const array<T, size>& arr) {
  os << "{"; string sep; for(const auto& x : arr) os << sep << x, sep = ", "; return os << "}"; 
}

template<typename A, typename B> ostream& operator<<(ostream &os, const pair<A, B> &p) { 
  return os << '(' << p.first << ", " << p.second << ')'; 
}

constexpr int ms = 1e6 + 3;

ll powmod(ll a, ll b, ll mod)
{
    a %= mod;assert(b >= 0);
    ll res = 1;
    for(;b;b>>=1)
    {
        if(b&1) res = (res * a) % mod;
        a = (a * a) % mod;
    }
    return res;
}

template<ll MOD>
ll norm( ll val ){
    val %= MOD;
    if( val < 0) val += MOD;
    return val;
}

constexpr ll p0 = 1000'000'021;
constexpr ll p1 = 1000'000'007;
constexpr int base = 31; // should be a little bit larger than the alphabet..

long long ppow[2][ms];

// Remember to call init() function!
struct Hash {
    // check if length matters to the specific problem!
    
    int len = 0; // does not always matter, depends on the problem
    long long H[2] = {0LL, 0LL};
    bool operator != (const Hash& rhs) const { return (H[0] != rhs.H[0] || H[1] != rhs.H[1]); }
    
    // check if len should be using in this operator.. depends on the problem
    bool operator == (const Hash& rhs) const { return ( ( H[0] == rhs.H[0] && H[1] == rhs.H[1]) && len == rhs.len); }
    
    Hash(ll h0 = 0, ll h1 = 0) { H[0] = norm<p0>(h0); H[1] = norm<p1>(h1); } 
    
    inline void add_back(char c) {
        H[0] = (H[0] + (c - 'a' + 1) * ppow[0][len]) % p0;
        H[1] = (H[1] + (c - 'a' + 1) * ppow[1][len]) % p1;
        ++len;
    }
    
    inline void add_front(char c) {
        H[0] = (H[0] * base + (c - 'a' + 1) ) % p0;
        H[1] = (H[1] * base + (c - 'a' + 1) ) % p1;
        ++len;
    }
    
    inline void removeBack(char c) {
        // assert( len > 0);
        H[0] = norm<p0>( H[0] - (c - 'a' + 1) * ppow[0][len]); 
        H[1] = norm<p1>( H[1] - (c - 'a' + 1) * ppow[1][len]);
        --len;
    }
    
    inline void removeFront(char c)
    {
        //assert(len > 0);
        H[0] = norm<p0>( H[0] - (c - 'a' + 1) );
        ll invMod = powmod( ppow[0][len - 1], p0 - 2, p0);
        H[0] = (H[0] * invMod) % p0;
        H[1] = norm<p1>( H[1] - (c - 'a' + 1) );
        invMod = powmod( ppow[1][len - 1], p1 - 2, p1);
        H[1] = (H[1] * invMod) % p1;
        --len;
    }

    void addString( const string& s) { for(const char& c : s) add_back(c); }

    ll combine() {
      return H[0] * H[1] + H[0]; 
    }
};

void init() 
{
    ppow[0][0] = ppow[1][0] = 1;
    rep(i, 1, ms) 
    {
        ppow[0][i] = (ppow[0][i - 1] * base ) % p0;
        ppow[1][i] = (ppow[1][i - 1] * base ) % p1;    
    }
}

map<ll, string> f[ms];
vector<string> tudo[ms];

int main() {
  init();
  buff();
  int n;
  cin >> n;
  vi single(26, 0);
  int max_len = 0;
  rep(i, 0, n) {
    string x;
    cin >> x;
    if(sz(x) == 1) single[x[0] - 'a']++;
    else {
      string nd;
      auto REX = Hash();
      rep(z, 1, sz(x)) REX.add_back(x[z]);
      f[sz(x) - 1][REX.combine()] += x[0];
    }
    tudo[sz(x)].push_back(x);
    remax(max_len, sz(x));
  }
  long long res = 0;
  for(int i = max_len; i >= 2; --i) {
    // vamos lidar com strings de tamanho i...
    for(const auto& v : tudo[i]) {
      vi freq(26, 0);
      for(const auto& c : v) freq[c - 'a']++;
      rep(j, 0, 26) if(freq[j]) res += single[j];
      auto REX = Hash(); 
      int search_len = 0;
      for(int add = i - 1; add > 1; --add) {
        REX.add_front(v[add]);
        freq[v[add] - 'a']--; 
        search_len++;
        for(const auto& c : f[search_len][REX.combine()]) {
          if(freq[c - 'a']) {
            res++; 
          } 
        } 
      } 
    }
  }
  cout << res << '\n';
  return 0;
}



Measured memory_bytes: 168568