//{{{
#include<algorithm>
#include<cmath>
#include<deque>
#include<fstream>
#include<iomanip>
#include<iostream>
#include<map>
#include<numeric>
#include<queue>
#include<random>
#include<set>
#include<sstream>
#include<sys/time.h>
#include<unordered_map>
#include<unordered_set>
#include<vector>
using ll = long long;
enum : int { M = (int)1e9 + 7 };
enum : ll { MLL = (ll)1e18L + 9 };
using namespace std;
#ifdef LOCAL
#include"rprint2.hpp"
#else
#define FUNC(name) template <ostream& out = cout, class... T> void name(T&&...){ }
FUNC(printde) FUNC(printdbe) FUNC(printdwe) FUNC(printdu) FUNC(printe) FUNC(printe0);
#endif
template <template <class T, class = std::allocator<T>> class V, class E>
istream& operator >> (istream& in, V<E>& v){ for(auto& e : v){ in >> e; } return in; }
//}}}

struct Node{
	char ch;
	Node* par = nullptr;
	vector<Node*> dests = vector<Node*>(26);
	// map<char, Node*> dests;
    int nums[26] = {};
    bool leaf = false;
	Node(){ }
	Node(Node* n):Node() { par = n; }
	Node* add(string& str, vector<int>& azs, int idx = -1){
        if(idx >= 0){
            ch = str[idx];
            azs[ch - 'a']--;
        }
        for(int i = 0; i < 26; i++){
            nums[i] += azs[i] > 0;
        }
        printde(ch, nums);
		if((int)str.size() == idx + 1){ leaf = true; return this; }
		char next = str[idx + 1] - 'a';
		// char next = str[idx + 1];
		if(!dests[next]){
		// if(!dests.count(next)){
			dests[next] = new Node(this);
		}
		return dests[next]->add(str, azs, idx + 1);
	}

	ll calc(){
        ll ret = 0;
        printde(ch, dests.size());
        if(leaf){
            ret = par->nums[ch - 'a'] - 1;
            printde(ch, ret, par->ch, par->nums[ch - 'a']);
        }
        for(auto& dest : dests){
            if(dest){
                ret += dest->calc();
            }
            // ret += dest.second->calc();
        }
        return ret;
    }
};

struct Trie {
    struct Node {
        char ch;
        map<char, int> dests;
        int parentIdx;
        int nums[26] = {};
        bool leaf = false;
        bool isRoot(){ return !ch; }
    };
    vector<Node> nodes;
    void add(string& s, vector<int>& azs, int sidx = -1, int nidx = 0, int pidx = -1){
        if(nidx >= (int)nodes.size()){
            nodes.push_back({});
        }
        auto& dests = nodes[nidx].dests;
        nodes[nidx].ch = sidx >= 0 ? s[sidx] : 0;
        nodes[nidx].parentIdx = pidx;

        if(!nodes[nidx].isRoot()){
            azs[nodes[nidx].ch - 'a']--;
            for(int i = 0; i < 26; i++){
                nodes[nidx].nums[i] += azs[i] > 0;
            }
        }
        // printde(nodes[nidx].ch, nodes[nidx].nums);

		if(sidx + 1 == (int)s.size()){ nodes[nidx].leaf = true; return; }
		char next = s[sidx + 1];
		if(!dests.count(next)){
            dests[next] = nodes.size();
            add(s, azs, sidx + 1, nodes.size(), nidx);
		}else{
            add(s, azs, sidx + 1, dests[next], nidx);
        }
        printde(nodes[nidx].ch);
        // printde(nodes[nidx].ch, nodes[nidx].dests);
    }

    ll calc(int nidx = 0){
        ll ret = 0;
        printde(nodes[nidx].ch, nodes[nidx].dests);
        if(nodes[nidx].leaf){
            ret = nodes[nodes[nidx].parentIdx].nums[nodes[nidx].ch - 'a'] - 1;
            // printde(nodes[nidx].ch, ret, nodes[nodes[nidx].parentIdx].ch, nodes[nodes[nidx].parentIdx].nums[nodes[nidx].ch - 'a']);
        }
        for(auto& dest : nodes[nidx].dests){
            ret += calc(dest.second);
        }
        return ret;
    }
};

int main(){
    cin.tie(0); ios::sync_with_stdio(false);
    int n; cin >> n;
    Node root;
    // Trie root;
    // root.nodes.reserve(100000);
    vector<int> azs(26);
    for(int i = 0; i < n; i++){
        string s; cin >> s;
        reverse(s.begin(), s.end());
        azs.assign(26, 0);
        for(auto& c : s){
            azs[c - 'a']++;
        }
        root.add(s, azs);
    }
    cout << root.calc() << '\n';
}
/*
a
ba
abc
dabc
eabdc
*/


Measured memory_bytes: 403856