Problem:
Score : 700 points

Problem Statement

Limak can repeatedly remove one of the first two characters of a string,
for example abcxyx \rightarrow acxyx \rightarrow cxyx \rightarrow cyx.

You are given N different strings S_1, S_2, \ldots, S_N.
Among N \cdot (N-1) / 2 pairs (S_i, S_j),
in how many pairs could Limak obtain one string from the other?

Constraints

2 \leq N \leq 200\,000

S_i consists of lowercase English letters a-z.

S_i \neq S_j

1 \leq |S_i|

|S_1| + |S_2| + \ldots + |S_N| \leq 10^6

Input

Input is given from Standard Input in the following format.

N
S_1
S_2
\vdots
S_N

Output

Print the number of unordered pairs (S_i, S_j)
where i \neq j and Limak can obtain one string from the other.

Sample Input 1

3
abcxyx
cyx
abc

Sample Output 1

1

The only good pair is (abcxyx, cyx).

Sample Input 2

6
b
a
abc
c
d
ab

Sample Output 2

5

There are five good pairs: (b, abc), (a, abc), (abc, c), (b, ab), (a, ab).

Solution in C++ (GCC 9.2.1) (judge verdict: Wrong Answer)

#include <bits/stdc++.h>
using namespace std;
template<class T> ostream& operator<<(ostream &os, vector<T> V) { os << "[ "; 
  for(auto v:V)os << v << " "; return os << "]";
}
template<class T> ostream& operator<<(ostream &os, set<T> S){ os << "{ "; 
  for(auto s:S) os<<s<<" ";  return os<<"}"; 
}
template<class L, class R> ostream& operator<<(ostream &os, pair<L,R> P) {
  return os<<"("<<P.first<<","<< P.second << ")";
}
template<class L, class R> ostream& operator<<(ostream &os, map<L,R> M) {
  os<<"{ ";for(auto m:M)os<<"("<<m.first<<":"<<m.second<<")";
  return os<<"}";
}
#define cerr cout
#define TRACE
#ifdef TRACE
#define trace(...) __f(#__VA_ARGS__, __VA_ARGS__)
template <typename Arg1>
void __f(const char* name, Arg1&& arg1){
  cerr << name << " : " << arg1 << std::endl;
}
template <typename Arg1, typename... Args>
void __f(const char* names, Arg1&& arg1, Args&&... args){
  const char* comma = strchr(names + 1, ',');cerr.write(names, comma - names) << " : " << arg1<<" | ";__f(comma+1, args...);
}
#else
#define trace(...) 1
#endif
 #include <ext/pb_ds/assoc_container.hpp> 
// #include <ext/pb_ds/tree_policy.hpp> 
 using namespace __gnu_pbds;
// #define ordered_set tree<int, null_type,less<int>, rb_tree_tag,tree_order_statistics_node_update>
// find_by_order(k)  returns iterator to kth element starting from 0;
// order_of_key(k) returns count of elements strictly smaller than k;
//For multiset use less_equal operator but it does support erase operations for multiset
#define ll long long
#define ld long double
#define vll vector<ll>
#define pll pair<ll,ll>
#define vpll vector<pll>
#define I insert 
#define pb push_back
#define F first
#define S second
//#define endl "\n"
#define all(v) (v).begin(),(v).end()
typedef vector<int> vi;
typedef pair<int,int> pii;
typedef pair<pii,int> ppi;
typedef vector<pii> vpii;
#define fio ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL)
#define mp make_pair


const int mod = 1e9+7;

inline int add(int a,int b){a+=b;if(a>=mod)a-=mod; return a;} 
inline int sub(int a,int b){a-=b;if(a<0) a += mod; return a;}
inline int mul(int a, int b){ return a*1ll*b%mod;}
inline int power(int x, ll y){
  int res = 1;
  while(y){
    if(y&1) res = mul(res , x);
    x = mul(x,x);
    y >>= 1;
  }
  return res;
}
const int N = 2e5 + 100;
const int ALP = 26;
vector< int > v;
struct Trie{
  //vector<int> node;
  vector<gp_hash_table<char,int> > edge;
  vector<vector<int> > present; 
  int curr = 0;
  int newNode(){
    gp_hash_table<char,int> m;
    edge.pb(m);
    vector<int> v;
    present.pb(v);
    return curr++;
  }
  void init(){
    edge.clear();
    present.clear();
    edge.reserve(1000);
    present.reserve(1000);
    curr = 0;
    newNode();
  }

  void addWord(const string &s){
    //cout << "adding word: " << s << endl;
    int root = 0;
    int id = 0;

    if(present[root].size() == 0){
     present[root].resize(ALP);
     for(int i = 0;i < ALP; ++i) present[root][i] = 0;
    }
    vector<bool> valid(ALP,false);
    for(int i = 0;i < s.size(); ++i)
      valid[s[i]-'a'] = true;
    for(int i = 0;i < ALP;  ++i){
      if(valid[i]){
       present[root][i]++;
     }
    }

    for(int i = 0;i < s.size() ; ++i){
      if(edge[root].find(s[s.size()-1-i]) == edge[root].end())
        edge[root][s[s.size()-1-i]] = newNode();
      root = edge[root][s[s.size()-1-i]];
      if(v[id] == i+2){
        //cout << s << ' ' << id << ' ' << v[id] << endl;
        if(present[root].size() == 0){
         present[root].resize(ALP);
         for(int i = 0;i < ALP; ++i) present[root][i] = 0;
        }
        vector<bool> valid(ALP,false);
        for(int i = 0;i < s.size()-i; ++i)
          valid[s[i]-'a'] = true;
        for(int i = 0;i < ALP;  ++i){
          if(valid[i]){
           present[root][i]++;
         }
        }
        ++id;
      }
    }
    //cout << "added word: " << s << endl;
  }
  int query(int len, const string &s, char c){
    //cout << "querying word: " << s << endl;
    int root = 0;
    for(int i = 0;i < len ; ++i){
      if(edge[root].find(s[s.size()-1-i]) == edge[root].end()) return 0;
      root = edge[root][s[s.size()-1-i]];
    }
    if(present[root].size() == 0) return 0;
    return present[root][c-'a'];
  }
};
const int L = 1e6 + 100;

vector<string> A[L];
//Trie trr;

int main(){
  fio; cout<<fixed<<setprecision(25);	
  int n; cin >> n;
  string s;
  for(int i =1;i <= n ; ++i){
    cin >> s;
    A[s.size()].pb(s);
  }
  for(int i = 1;i < L; ++i){
    if(A[i].size() != 0) v.push_back(i);
  }
  //cout << v << endl;
  ll ans = 0;
  for(int i = 0;i < v.size() ; ++i){
    //for(int k = 0;k < i; ++k){
      Trie trr;
      trr.init();
      for(int j = 0;j < A[v[i]].size(); ++j){
        trr.addWord(A[v[i]][j]); 
      }
      for(int k = 0;k < i; ++k){
        for(int j = 0;j < A[v[k]].size(); ++j){
          ans += trr.query(v[k]-1, A[v[k]][j], A[v[k]][j][0] );
        }
      }
    //}
  }
  cout << ans << endl;


  return 0;
}