//header{{{
#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
#include <boost/sort/spreadsort/spreadsort.hpp>
//#include <boost/graph/adjacency_list.hpp>
//#include <boost/graph/dijkstra_shortest_paths.hpp>
//#include <boost/graph/graph_utility.hpp>
#include <boost/multiprecision/cpp_int.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>
  
using namespace std;
//using namespace boost::multiprecision;
//using namespace boost::math;

/*
typedef boost::adjacency_list<boost::listS, boost::vecS, boost::undirectedS,
        boost::no_property, boost::property<boost::edge_weight_t, int> > Graph;
*/

#define rep(i,n) for(int i=0;i<(n);++i)
#define reps(i,n) for(int i=1;i<=(n);++i)
#define all(x) (x).begin(),(x).end()
#define Fixed fixed << setprecision(12)
#define bsort boost::sort::spreadsort::spreadsort
#define int int_fast64_t
using pii = pair<int,int>;
constexpr int INF  = 0x3f3f3f3f;
constexpr long long LINF = 0x3f3f3f3f3f3f3f3fLL;
constexpr int mod1 = 1e9+7; 
constexpr int mod2 = 998244353;
template <class Func>

class FixPoint : Func {
public:
    explicit constexpr FixPoint(Func&& f) noexcept : Func(forward<Func>(f)) {}
 
    template <class... Args>
    constexpr decltype(auto) operator()(Args&&... args) const {
        return Func::operator()(*this, std::forward<Args>(args)...);
    }
};
 
template <class Func>
static inline constexpr decltype(auto) makeFixPoint(Func&& f) noexcept {
    return FixPoint<Func>{forward<Func>(f)};
}

template <class A, class B> inline bool chmax(A &a, const B &b) { return b > a && (a = b, true); }
template <class A, class B> inline bool chmin(A &a, const B &b) { return b < a && (a = b, true); }

template <class T> using min_heap = priority_queue<T,vector<T>,greater<T> >;
template <class T> using max_heap = priority_queue<T>;
template <class A, class B> using umap = unordered_map<A,B>;
  
inline int square(int a){ return a * a;}
inline int updiv(int a,int b){ return (a + b - 1) / b; }

constexpr int dx[] = {1,0,-1,0,1,1,-1,-1};
constexpr int dy[] = {0,-1,0,1,1,-1,-1,1};

struct negrightshift {
    inline int operator() (const int &x, const unsigned offset) {
        return -(x >> offset);
    }
};
//}}}

template <int char_size, int base>
struct Trie {
    struct Node {
        vector<int> nxt;
        vector<int> accept;
        int c;
        int common;
        vector<int> cmn;
        Node(int c_) : c(c_), common(0) {
            nxt.assign(char_size, -1);
            cmn.assign(27, 0);
        }
    };
 
    vector<Node> nodes;
    int root;
 
    Trie() : root(0) {
        nodes.emplace_back(root);
    }
 
    // 文字列の挿入
    void insert(const string &ward, int ward_id) {
        int node_id = 0;
        for (const auto e: ward) {
            const int c = int(e - base);
            int &nxt_id = nodes[node_id].nxt[c];
            if (nxt_id == -1) {
                nxt_id = (int) nodes.size();
                nodes.emplace_back(c);
            }
            nodes[node_id].common++;
            node_id = nxt_id;
        }
        nodes[node_id].common++;
        nodes[node_id].accept.emplace_back(ward_id);
    }

    void insert(const string &ward, int ward_id, vector<int>& cnt) {
        int node_id = 0;
        for(int i = 0; i < 26; ++i){
            nodes[node_id].cmn[i] += (cnt[i] != 0);
        }
        for (const auto e: ward) {
            const int c = int(e - base);
            int &nxt_id = nodes[node_id].nxt[c];
            if (nxt_id == -1) {
                nxt_id = (int) nodes.size();
                nodes.emplace_back(c);
            }
            nodes[node_id].common++;
            node_id = nxt_id;
            --cnt[c];
            for(int i = 0; i < 26; ++i){
                nodes[node_id].cmn[i] += (cnt[i] != 0);
            }
        }
        nodes[node_id].common++;
        nodes[node_id].cmn[26]++;
        nodes[node_id].accept.emplace_back(ward_id);
    }

    void insert(const string &ward) {
        vector<int> cnt(26);
        for(auto &&e : ward){
            cnt[e - base]++;
        }
        insert(ward, nodes[0].common, cnt);
    }
 
    // 文字列の検索
    bool search(const string &word, bool prefix = false) {
        int node_id = 0;
        for (const auto e: word) {
            const int c = int(e - base);
            const int nxt_id = nodes[node_id].nxt[c];
            if (nxt_id == -1) {
                return false;
            }
            node_id = nxt_id;
        }
        return ((prefix) ? true : nodes[node_id].accept.size() > 0);
    }
 
    // 指定した接頭辞 (prefix) を持つ文字列の検索
    bool prefixSearch(const string &prefix) {
        return search(prefix, true);
    }
 
    // 指定した接頭辞 (prefix) を持つ文字列の総数
    int prefixCount(const string &prefix) {
        int node_id = 0;
        for (const auto e: prefix) {
            const int c = int(e - base);
            const int nxt_id = nodes[node_id].nxt[c];
            if (nxt_id == -1) {
                return 0;
            }
            node_id = nxt_id;
        }
        return nodes[node_id].common;
    }

    int prefixCount(const string &prefix, char x) {
        int node_id = 0;
        for (const auto e: prefix) {
            const int c = int(e - base);
            const int nxt_id = nodes[node_id].nxt[c];
            if (nxt_id == -1) {
                return 0;
            }
            node_id = nxt_id;
        }
        //return nodes[node_id].common;
        return (nodes[node_id].cmn[x - base]);
    }
  
    // 挿入した文字列の総数
    int count() const {
        return nodes[0].common;
    }
 
    // 頂点の総数
    int size() const {
        return (int) nodes.size();
    }
};

signed main(){
    cin.tie(nullptr);
    ios_base::sync_with_stdio(false);
    cout.setf(ios_base::fixed);
    cout.precision(10);

    int n;
    cin >> n;

    vector<string> s(n);

    Trie<26, 'a'> trie;

    vector<vector<int> > cnt(n, vector<int>(26));

    rep(i,n){
        cin >> s[i];
    }

    sort(all(s), [](string &a, string& b){
        return (a.size() > b.size());
    });

    rep(i,n){
        reverse(all(s[i]));
        for(auto&& e : s[i]){
            ++cnt[i][e - 'a'];
        }
    }

    int res = 0;

    for(int i = 0; i < n; ++i){
        res += trie.prefixCount(s[i].substr(0, s[i].size()-1), s[i].back());
        trie.insert(s[i]);
    }

    cout << res << '\n';
    
    return 0;
}

Measured memory_bytes: 527164