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# (.NET Core 3.1.201) (judge verdict: Accepted)

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

class TEST{
	static void Main(){
		Sol mySol =new Sol();
		mySol.Solve();
	}
}

class Sol{
	public void Solve(){
		
		Array.Sort(S, (s, t) => s.Length.CompareTo(t.Length));
		
		var ca = new List<char>();
		int[] ofs = new int[N];
		for(int i=0;i<N;i++){
			for(int j=0;j<S[i].Length;j++){
				ca.Add(S[i][j]);
			}
			if(i > 0){
				ofs[i] = ofs[i-1] + S[i-1].Length;
			}
		}
		var T = new String(ca.ToArray());
		var RH = new RollingHash2(T);
		
		
		var di = new Dictionary<long, int[]>();
		for(int i=0;i<N;i++){
			int n = S[i].Length;
			int[] hs = new int[n];
			for(int j=0;j<n;j++){
				hs[j] = 1 << (int)(S[i][j] - 'a');
				if(j > 0) hs[j] |= hs[j - 1];
			}
			
			if(!di.ContainsKey(0)) di.Add(0, new int[26]);
			for(int j=0;j<26;j++){
				if((hs[n-1] >> j) % 2 == 1) di[0][j]++;
			}
			
			for(int j=n-1;j>=1;j--){
				var hash = RH.GetHash(j + ofs[i], n - j);
				if(!di.ContainsKey(hash)) di.Add(hash, new int[26]);
				for(int k=0;k<26;k++){
					if((hs[j-1] >> k) % 2 == 1) di[hash][k]++;
				}
			}
		}
		
		
		long cnt = 0;
		for(int i=0;i<N;i++){
			int n = S[i].Length;
			long tailhash = S[i].Length == 1 ? 0 : RH.GetHash(1 + ofs[i], n - 1);
			int head = (int)(S[i][0] - 'a');
			
			long c0 = di[tailhash][head];
			cnt += c0;
		}
		
		cnt -= N;
		
		Console.WriteLine(cnt);
		
		
		
		
		
	}
	int N;
	String[] S;
	public Sol(){
		N = ri();
		S = new String[N];
		for(int i=0;i<N;i++) S[i] = rs();
	}

	static String rs(){return Console.ReadLine();}
	static int ri(){return int.Parse(Console.ReadLine());}
	static long rl(){return long.Parse(Console.ReadLine());}
	static double rd(){return double.Parse(Console.ReadLine());}
	static String[] rsa(char sep=' '){return Console.ReadLine().Split(sep);}
	static int[] ria(char sep=' '){return Array.ConvertAll(Console.ReadLine().Split(sep),e=>int.Parse(e));}
	static long[] rla(char sep=' '){return Array.ConvertAll(Console.ReadLine().Split(sep),e=>long.Parse(e));}
	static double[] rda(char sep=' '){return Array.ConvertAll(Console.ReadLine().Split(sep),e=>double.Parse(e));}
}


class RollingHash2{
	String S;
	RollingHash Left, Right, Mid;
	public RollingHash2(String S_){
		S = S_;
		Left = new RollingHash(S, 2525, (long) 1e9 + 7);
		Right = new RollingHash(S, 1234567, (long) 1e9 + 9);
		Mid = new RollingHash(S, 75835, (long) 1e9 + 7);
	}
	public long GetHash(int strt,int len){
		long h1 = Left.GetHash(strt, len);
		long h2 = Right.GetHash(strt, len);
		long h3 = Mid.GetHash(strt, len);
		long hh = (((h1 << 5) + h1) ^ h2);
		
		return (((hh << 5) + hh) ^ h3);
	}
	
}



class RollingHash{
	
	long[] Hash;
	long[] Base;
	String S;
	long mod;
	int N;
	
	public RollingHash(String s_,long base_=2525,long mod_=(long)1e9+7){
		mod=mod_;
		S=s_;
		N=S.Length;
		Hash=new long[N+1];
		
		Base=new long[N+1];
		Base[0]=1;
		Base[1]=base_;
	
		for(int i=1;i<N;i++){
			Base[i+1]=Base[i]*Base[1];
			if(Base[i+1]>=mod)Base[i+1]%=mod;
		}
		
		Hash[0]=0;
		Hash[1]=(long)S[0];
		for(int i=1;i<N;i++){
			Hash[i+1]=Hash[i]*Base[1]+(long)S[i];
			if(Hash[i+1]>=mod)Hash[i+1]%=mod;
		}
	}
	
	public long GetHash(int strt,int len){
		//return hash of S.Substring(strt,len);
		if(len==0)return 0;
		if(strt+len>=N)len=N-strt;
		long ret=Hash[strt+len]+mod-(Hash[strt]*Base[len]>=mod?Hash[strt]*Base[len]%mod:Hash[strt]*Base[len]);
		return ret>=mod?ret%mod:ret;
	}
	

}