#include<bits/stdc++.h>
//#include<atcoder/all>
using namespace std;
//using namespace atcoder;
typedef int64_t ll;
//using mint=modint998244353;
typedef unsigned long ulong;
typedef long double ld;
const ll MODA=998244353;
ll vx[4]={0,1,0,-1};
ll vy[4]={1,0,-1,0};
#define rep(i,n) for(ll i=0;i<(ll)(n);i++)
long long gcd(long long a,long long b){
a=abs(a);
b=abs(b);
ll gcdmax=max(a,b);
ll gcdmin=min(a,b);
if(gcdmin==0)return gcdmax;
while(true){
if(gcdmax%gcdmin==0)break;
else gcdmax%=gcdmin;
swap(gcdmin,gcdmax);
}
return gcdmin;
}
ll pow(ll N,ll P,ll M){
if(P==0)return 1;
else if(P%2==0){
ll t=pow(N,P/2,M);
return t*t%M;
}
else return N*pow(N,P-1,M)%M;
}
ll pow(ll N,ll P){
if(P==0)return 1;
else if(P%2==0){
ll t=pow(N,P/2);
return t*t;
}
else return N*pow(N,P-1);
}
vector<ll> fac;
vector<ll> finv;
vector<ll> inv;
void COMinit(ll N,ll P){
rep(i,N+1){
if(i==0){
fac.push_back(1);
finv.push_back(1);
inv.push_back(1);
}
else if(i==1){
fac.push_back(1);
finv.push_back(1);
inv.push_back(1);
}
else{
fac.push_back(fac.at(i-1)*i%P);
inv.push_back(P-inv.at(P%i)*(P/i)%P);
finv.push_back(finv.at(i-1)*inv.at(i)%P);
}
}
}
ll COM(ll n,ll k,ll P){
if(n<k)return 0;
if(n<0||k<0)return 0;
return fac.at(n)*(finv.at(k)*finv.at(n-k)%P)%P;
}
struct UnionFind {
vector<ll> par; // par[i]:iの親の番号 (例) par[3] = 2 : 3の親が2
UnionFind(ll N) : par(N) { //最初は全てが根であるとして初期化
for(ll i = 0; i < N; i++) par[i] = i;
}
ll root(ll x) { // データxが属する木の根を再帰で得る:root(x) = {xの木の根}
if (par[x] == x) return x;
return par[x] = root(par[x]);
}
void unite(ll x, ll y) { // xとyの木を併合
ll rx = root(x); //xの根をrx
ll ry = root(y); //yの根をry
if (rx == ry) return; //xとyの根が同じ(=同じ木にある)時はそのまま
par[rx] = ry; //xとyの根が同じでない(=同じ木にない)時:xの根rxをyの根ryにつける
}
bool same(ll x, ll y) { // 2つのデータx, yが属する木が同じならtrueを返す
ll rx = root(x);
ll ry = root(y);
return rx == ry;
}
};
const ulong MASK30 = (1UL << 30) - 1;
const ulong MASK31 = (1UL << 31) - 1;
const ulong MOD = (1UL << 61) - 1;
const ulong MASK61 = MOD;
//mod 2^61-1を計算する関数
ulong CalcMod(ulong x)
{
ulong xu = x >> 61;
ulong xd = x & MASK61;
ulong res = xu + xd;
if (res >= MOD) res -= MOD;
return res;
}
//a*b mod 2^61-1を返す関数(最後にModを取る)
ulong Mul(ulong a, ulong b)
{
ulong au = a >> 31;
ulong ad = a & MASK31;
ulong bu = b >> 31;
ulong bd = b & MASK31;
ulong mid = ad * bu + au * bd;
ulong midu = mid >> 30;
ulong midd = mid & MASK30;
return CalcMod(au * bu * 2 + midu + (midd << 31) + ad * bd);
}
int main(){
ll N;
cin>>N;
vector<string> S(N);
map<pair<ulong,ll>,int> mp;
ll v=0;
mt19937_64 rng(time(0));
ulong base= rng() % MOD;
ulong base2 =rng()%MODA;
rep(i,N){
cin>>S[i];
v+=S[i].size();
ulong hs=0;
ulong hs2=0;
rep(j,S[i].size()){
ulong c=(S[i][j]-'a');
c++;
hs=CalcMod(Mul(hs,base)+c);
hs2=CalcMod(Mul(hs2,base2)+c);
mp[{hs,hs2}]++;
}
}
ll ans=2*N*v;
rep(i,N)reverse(S[i].begin(),S[i].end());
rep(i,N){
cin>>S[i];
v+=S[i].size();
ulong hs=0;
ulong hs2=0;
rep(j,S[i].size()){
ulong c=(S[i][j]-'a');
c++;
hs=CalcMod(Mul(hs,base)+c);
hs2=CalcMod(Mul(hs2,base2)+c);
ans-=2*mp[{hs,hs2}];
}
}
cout<<ans<<endl;
}
238. Product of Array Except Self | 229. Majority Element II |
222. Count Complete Tree Nodes | 215. Kth Largest Element in an Array |
198. House Robber | 153. Find Minimum in Rotated Sorted Array |
150. Evaluate Reverse Polish Notation | 144. Binary Tree Preorder Traversal |
137. Single Number II | 130. Surrounded Regions |
129. Sum Root to Leaf Numbers | 120. Triangle |
102. Binary Tree Level Order Traversal | 96. Unique Binary Search Trees |
75. Sort Colors | 74. Search a 2D Matrix |
71. Simplify Path | 62. Unique Paths |
50. Pow(x, n) | 43. Multiply Strings |
34. Find First and Last Position of Element in Sorted Array | 33. Search in Rotated Sorted Array |
17. Letter Combinations of a Phone Number | 5. Longest Palindromic Substring |
3. Longest Substring Without Repeating Characters | 1312. Minimum Insertion Steps to Make a String Palindrome |
1092. Shortest Common Supersequence | 1044. Longest Duplicate Substring |
1032. Stream of Characters | 987. Vertical Order Traversal of a Binary Tree |