#include <bits/stdc++.h>

//Common
using namespace std;using f64 = double;using i64=long long;using u64=unsigned long long;
template<typename T> using Arr=vector<T>;template<typename T> using Func=function<T>;template<typename T> using Str=basic_string<T>;
#define hfor(v, s, e) for(int v=(s);(s)<=v&&v<(e);++v)//half-opened range
#define hfori(v, s, e) for(int v=(e)-1;(s)<=v&&v<(e);--v)//inversion
#define hforo(v, s, e) int v=(s);for(;(s)<=v&&v<(e);++v)//out declaration
#define hforoi(v, s, e) int v=(e)-1; for(;(s)<=v&&v<(e);--v)
#define cfor(v, s, e) hfor(v,(s),(e)+1)//closed range
#define cfori(v, s, e) hfori(v,(s),(e)+1)
#define cforo(v, s, e) hforo(v,(s),(e)+1)
#define cforoi(v, s, e) hforoi(v,(s),(e)+1)
#define rep(v,x) hfor(v,0,(x))
#define repi(v,x) hfori(v,0,(x))
#define repo(v,x) hforo(v,0,(x))
#define all(x) (x).begin(),(x).end()
#define pushb push_back
#define pushf push_front
#define popb pop_back
#define popf pop_front
#define empl emplace
#define emplb emplace_back
#define emplf emplace_front
#define fi first
#define se second
#define mkp make_pair
#define mkt make_tuple
#define cxp constexpr
#define PQMAX(...) std::priority_queue<__VA_ARGS__>
#define PQMIN(...) std::priority_queue<__VA_ARGS__,Arr<__VA_ARGS__>,greater<__VA_ARGS__>>

//Math
template<typename T> cxp T inf() { return numeric_limits<T>::max() / 2; }
template<typename T> inline T sq(T x){return x*x;}
cxp int lgc(int x){return 64-__builtin_clzll(x-1);}
cxp int lgf(int x){return 63-__builtin_clzll(x);}
int rd(int lb, int ub){static mt19937 rng(time(0)^i64(new int)); return uniform_int_distribution<int>(lb, ub-1)(rng);}
int rd(int ub=inf<int>()){return rd(0,ub);}
const f64 pi=acosl(-1), eps=1e-10;

//IO
template<typename T>ostream& operator<<(ostream& s, const Arr<T>& a) {for(auto i:a) cout<<i<<' '; return s;}
auto cinint(){i64 x;cin>>x;return x;}
auto cinchr(){char x;cin>>x;return x;}
auto cinints(int n){Arr<i64> a(n);for(auto&i:a)cin>>i;return a;}
#ifndef DEBUG
	//#pragma GCC optimize ("Ofast") //somtimes it become more slower
	auto __PRE_RUN__=(ios::sync_with_stdio(0), cin.tie(0), cout.tie(0),(cout<<fixed<<setprecision(11)), 0);
#endif

//Misc
int sz(const auto& x){return x.size();}
auto split(auto s, auto p){
	Arr<decltype(s)> ret;
	auto it1=s.begin();
	for(auto it2=it1; (it2 = find(it1,s.end(),p)) != s.end(); it1=it2+1)
		ret.pushb({it1, it2});
	ret.pushb({it1,s.end()});
	return ret;
}
template<typename T> T rev(const T& a){return {a.rbegin(),a.rend()};}
Arr<int> range(int n){ Arr<int> ret(n); rep(i,n)ret[i]=i; return ret; }
struct defer{ defer(auto f):f(f){} ~defer(){f();} function<void()> f; };
#define defer(x) auto _##__COUNTER__ = defer([&](){x;});
#define lam(expr, ...) [&](__VA_ARGS__){return expr;}
#define reduce accumulate
template<class... A>
auto ARR(auto n, A&&...a){
	if constexpr(sizeof...(a)==0) return n;
	else return vector(n,ARR(a...));
}
#define XA(name,mn,mx) int& name(int i){\
	static int a[mx-mn+1];\
	return a[i-mn];\
}
#define lb lower_bound
#define ub upper_bound

struct HashVal{
	u64 h[2];
	HashVal(u64 h1=0, u64 h2=0, int cnt=0):cnt(cnt){ h[0]=h1; h[1]=h2; }
	
	void push_back(HashVal x){ rep(i,2) h[i]*=p[i], h[i]+=x.h[i]; cnt++; }
	void push_front(HashVal x){ rep(i,2) h[i]+=x.h[i]*fp(p[i],cnt); cnt++; }
	void pop_back(HashVal x){ rep(i,2) h[i]-=x.h[i], h[i]*=inv(p[i]); cnt--; }
	void pop_front(HashVal x){ rep(i,2) h[i]-=x.h[i]*fp(p[i],cnt-1); cnt--; }
	
	void insert(HashVal x){ rep(i,2) h[i]+=fp(p[i], x.h[i]); cnt++; }
	void erase(HashVal x){ rep(i,2) h[i]-=fp(p[i], x.h[i]); cnt--; }

	int size()const{return cnt;}
	
	HashVal operator+(const HashVal& r)const{return HashVal(h[0]+r.h[0], h[1]+r.h[1], cnt+r.cnt);}
	HashVal operator-(const HashVal& r)const{return HashVal(h[0]-r.h[0], h[1]-r.h[1], cnt+r.cnt);}
	HashVal operator+=(const HashVal& r){return *this=*this+r;}
	HashVal operator-=(const HashVal& r){return *this=*this-r;}
	HashVal operator-()const{return HashVal(-h[0], -h[1]);}
	bool operator==(const HashVal& r)const{return h[0]==r.h[0]&&h[1]==r.h[1];}
	bool operator<(const HashVal& r)const{return h[0]==r.h[0]?h[1]<r.h[1]:h[0]<r.h[0];}
	
private:
	int cnt;
	static cxp u64 p[2]={u64(1e9+9), u64(1e9+7)};
	
	//지금은 cnt 길이가 가변이라 cxp효과를 못받지만, 직접 짜거나 개선하면 cxp효과로 log제거 가능하다.
	cxp u64 fp(u64 x, u64 p){
		if(!p)
			return 1;
		u64 z=fp(x,p/2);
		return z*z*(p%2?x:1);
	}
	//inverse of p in modulo 2^64 (see euler's theorem)
	cxp u64 inv(u64 x){ return fp(x,9223372036854775807); }
};

ostream& operator<<(ostream& s, const HashVal& n) { return s<<'('<<(unsigned)n.h[0]<<','<<(unsigned)n.h[1]<<')'; }

#define endl '\n'//not interactive?
#define int i64//MLE?
using pint = pair<int,int>;
using tint = tuple<int,int,int>;

signed main(){
	int n; cin>>n;
	map<int,Arr<string>> a;
	rep(i,n){
		string s; cin>>s;
		a[sz(s)].pushb(s);
	}
	Arr<tuple<HashVal,string,array<int,26>>> b;
	int ans=0;
	hfori(len,1,int(1e6+1)){
		map<HashVal,array<int,26>> z;
		for(auto& [h,s,c]:b){
			h.popf(s[sz(s)-len]);
			c[s[sz(s)-len]-'a']=1;
			rep(i,26)
				z[h][i]+=c[i];
		}
		for(auto i:a[len]){
			HashVal h;
			for(auto c:i)h.pushb(c);
			h.popf(i.front());
			array<int,26> c{}; c[i.front()-'a']=1;
			b.pushb({h,i,c});
			ans+=z[h][i.front()-'a'];
		}
	}
	cout<<ans<<endl;
}


Measured memory_bytes: 184096