#pragma region header
// #pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
#define all(a) begin(a), end(a)
#define rall(a) rbegin(a), rend(a)
#define mp make_pair
#define mt make_tuple
#define rep1(i, n) for (decltype(+n) i = 0; i < (n); i++)
#define rrep1(i, n) for (auto i = n - 1; i > static_cast<decltype(i)>(-1); i--)
#define rep2(i, a, b) for (auto i = (a); i < (b); i++)
#define rrep2(i, a, b) for (auto i = b - 1; i >= a; i--)
#define GET_MACRO(_1, _2, _3, NAME, ...) NAME
#define rep(...) GET_MACRO(__VA_ARGS__, rep2, rep1) (__VA_ARGS__)
#define rrep(...) GET_MACRO(__VA_ARGS__, rrep2, rrep1) (__VA_ARGS__)
#define each(i, a) for (auto &&i : (a))
using namespace std;

using ld = long double;
using vi = vector<int>;
using vvi = vector<vi>;
using vs = vector<string>;
using vvs = vector<vs>;
using vd = vector<ld>;
using vvd = vector<vd>;
using vb = vector<bool>;
using vvb = vector<vb>;
using pii = pair<int, int>;
using vp = vector<pii>;
using vvp = vector<vp>;
using mii = map<int, int>;
using vm = vector<mii>;
using vvm = vector<vm>;
template <class T, class U>
using umap = unordered_map<T, U>;
using umii = umap<int, int>;
using seti = set<int>;
template <class T>
using uset = unordered_set<T>;
using useti = uset<int>;
template <class T>
using less_queue = priority_queue<T>;
template <class T>
using greater_queue = priority_queue<T, vector<T>, greater<T>>;

template <class T>
void SORT(T &a) { stable_sort(all(a)); }
template <class T>
void RSORT(T &a) { stable_sort(rall(a)); }
template <class T>
void rev(T &a) { reverse(rall(a)); }
template <class T>
void uniq(T &a) { a.erase(unique(all(a)), end(a)); }
template <class T>
auto min_of(T a) { return *min_element(all(a)); }
template <class T>
auto max_of(T a) { return *max_element(all(a)); }
template <class T>
int sum_of(T a) { return accumulate(all(a), 0ll); }
template <class T, class U>
auto sum_of(T a, U init) { return accumulate(all(a), init); }
template <class T, class U>
int count_of(T a, U i) { return count(all(a), i); }
template <class T, class U>
bool has(T a, U i) { return find(all(a), i) != end(a); }
template <class T>
int sz(T a) { return a.size(); };

template <class T>
void COUT(T x) { cout << x << endl; }
template <class T, class U>
void COUT(T x, U y) { cout << x << ' ' << y << endl; }
template <class T, class U, class V>
void COUT(T x, U y, V z) { cout << x << ' ' << y << ' ' << z << endl; }
template <class T>
void CSP(T x) { cout << x << ' '; }
template <class T>
void CVEC(T v) {
  int c = v.size() - 1;
  for (size_t i = 0; i < c; i++) cout << v[i] << ' ';
  if (c > -1) cout << v[c];
  cout << endl;
}

template <class T>
bool amin(T &a, const T &b) {
  if (a > b) {
    a = b;
    return true;
  }
  return false;
}
template <class T>
bool amax(T &a, const T &b) {
  if (a < b) {
    a = b;
    return true;
  }
  return false;
}

constexpr int lshift(int x) noexcept { return 1ll << x; }
constexpr int popcount(unsigned int x) noexcept { return __builtin_popcountll(x); }
constexpr int least1(unsigned int x) noexcept { return __builtin_ffsll(x); }
constexpr int ceil_div(int x, int y) noexcept { return (x - 1) / y + 1; }

#pragma endregion header

struct rolling_hash {
  static const uint64_t mod = (1ull << 61ull) - 1;
  using uint128_t = __uint128_t;
  vector<uint64_t> hashed;
  static vector<uint64_t> power;
  const uint64_t base;

  static inline uint64_t add(uint64_t a, uint64_t b) {
    if ((a += b) >= mod) a -= mod;
    return a;
  }

  static inline uint64_t mul(uint64_t a, uint64_t b) {
    uint128_t c = (uint128_t)a * b;
    return add(c >> 61, c & mod);
  }

  static inline uint64_t generate_base() {
    mt19937_64 mt(chrono::steady_clock::now().time_since_epoch().count());
    uniform_int_distribution<uint64_t> rand(1, rolling_hash::mod - 1);
    return rand(mt);
  }

  static void init_power(size_t sz, uint64_t base) {
    power.assign(sz + 1, 0);
    power[0] = 1;
    for (int i = 0; i < sz; i++) power[i + 1] = mul(power[i], base);
  }

  rolling_hash() = default;

  rolling_hash(const string &s, uint64_t base) : base(base) {
    size_t sz = s.size();
    hashed.assign(sz + 1, 0);
    for (int i = 0; i < sz; i++) {
      hashed[i + 1] = add(mul(hashed[i], base), s[i]);
    }
  }

  template <typename T>
  rolling_hash(const vector<T> &s, uint64_t base) : base(base) {
    size_t sz = s.size();
    hashed.assign(sz + 1, 0);
    for (int i = 0; i < sz; i++) {
      hashed[i + 1] = add(mul(hashed[i], base), s[i]);
    }
  }

  uint64_t query(int l, int r) const {
    return add(hashed[r], mod - mul(hashed[l], power[r - l]));
  }

  static inline uint64_t combine(uint64_t h1, uint64_t h2, size_t h2len) {
    return add(mul(h1, power[h2len]), h2);
  }

  int lcp(const rolling_hash &b, int l1, int r1, int l2, int r2) const {
    assert(base == b.base);
    int len = min(r1 - l1, r2 - l2);
    int low = 0, high = len + 1;
    while (high - low > 1) {
      int mid = (low + high) / 2;
      if (query(l1, l1 + mid) == b.query(l2, l2 + mid)) low = mid;
      else high = mid;
    }
    return low;
  }
};
vector<uint64_t> rolling_hash::power;
/*
auto rh_base = rolling_hash::generate_base();
rolling_hash::init_power(1000000, rh_base);
*/

void solve(int n, vector<string> s) {
  auto rh_base = rolling_hash::generate_base();
  rolling_hash::init_power(1000000, rh_base);
  vector<u_int64_t> as(26);
  rep(i, 26)as[i] = rolling_hash(string(1, 'a' + i), rh_base).query(0, 1);
  umap<u_int64_t, int> hs;
  vector<rolling_hash> rhs;
  each(x, s){
    rolling_hash rh(x, rh_base);
    rhs.push_back(rh);
    hs[rh.query(0, sz(x))]++;
  }
  int ans = 0;
  rep(i, n) {
    string x = s[i];
    int l = sz(x);
    rolling_hash rh = rhs[i];
    int cm = 0;
    rep(j, l) {
      cm |= lshift(x[j] - 'a');
      auto h = rh.query(j + 1, l);
      int l2 = l - j - 1;
      rep(k, 26) {
        if((cm >> k) & 1){
          auto it = hs.find(rolling_hash::combine(as[k], h, l2));
          if(it != hs.end())ans += it->second;
        }
      }
    }
  }
  COUT(ans - n);
}


#pragma region main
signed main() {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  cout << fixed << setprecision(15);

  int n;
  cin >> n;
  vector<string> s(n);
  for(int i = 0 ; i < n ; i++){
    cin >> s[i];
  }
  solve(n, move(s));
}
#pragma endregion main

Measured memory_bytes: 42956