#include<bits/stdc++.h>
using namespace std;

using Int = long long;
using ll = long long;

template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b)a=b;};
template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b)a=b;};

template<typename T> void drop(T x){cout<<x<<endl;exit(0);};

vector<Int> zalgorithm(string s){
  Int n = s.size();
  vector<Int> a(n, 0);
  a[0] = n;
  Int i = 1, j = 0;
  while(i < n){
    while(i + j < n && s[j] == s[i+j]) j++;
    a[i] = j;
    if(j == 0){
      i++;
      continue;
    }

    Int k = 1;
    while(i+k<n&&k+a[k] < j) a[i+k] = a[k], k++;
    i += k;
    j -= k;
  }
  return a;
}

template<typename TF, typename TC>
struct PrimalDual{
  struct edge{
    Int to;
    TF cap;
    TC cost;
    Int rev;
    edge(){}
    edge(Int to, TF cap, TC cost, Int rev):to(to), cap(cap), cost(cost), rev(rev){}
  };

  static const TC INF;
  vector<vector<edge> > G;
  vector<TC> h, dist;

  vector<Int> prevv, preve;

  PrimalDual(){}
  PrimalDual(Int n):G(n), h(n), dist(n), prevv(n), preve(n){}

  void add_edge(Int u, Int v, TF cap, TC cost){
    G[u].emplace_back(v, cap, cost, G[v].size());
    G[v].emplace_back(u, 0, -cost, G[u].size()-1);
  }

  void dijkstra(Int s){
    struct P{
      TC first;
      Int second;
      P(TC first, Int second):first(first), second(second){}
      bool operator<(const P&a)const{return a.first < first;}
    };

    priority_queue<P> que;
    fill(dist.begin(), dist.end(), INF);

    dist[s] = 0;
    que.emplace(dist[s], s);
    while(!que.empty()){
      P p = que.top(); que.pop();
      Int v = p.second;
      if(dist[v] < p.first) continue;
      for(Int i=0;i<(Int)G[v].size();i++){
        edge &e = G[v][i];
        if(e.cap == 0) continue;
        if(dist[v] + e.cost + h[v] - h[e.to] < dist[e.to]){
          dist[e.to] = dist[v] + e.cost + h[v] - h[e.to];
          prevv[e.to] = v;
          preve[e.to] = i;
          que.emplace(dist[e.to], e.to);
        }
      }
    }
  }

  TC flow(Int s, Int t, TF f, Int &ok){
    TC res = 0;
    fill(h.begin(), h.end(),0);
    while(f > 0){
      dijkstra(s);
      if(dist[t] == INF){
        ok = 0;
        return res;
      }

      for(Int v=0;v<(Int)h.size();v++)
        if(dist[v] < INF) h[v] = h[v] + dist[v];

      TF d = f;
      for(Int v = t;v !=s;v=prevv[v])
        d = min(d, G[prevv[v]][preve[v]].cap);

      f -= d;
      res = res + h[t] * d;
      for(Int v=t;v!=s;v=prevv[v]){
        edge &e = G[prevv[v]][preve[v]];
        e.cap -= d;
        G[v][e.rev].cap += d;
      }
      ok = 1;
    }
    return res;
  }

};

template<typename TF, typename TC>
const TC PrimalDual<TF, TC>::INF = numeric_limits<TC>::max()/2;


Int same_str(string A,string B){
  Int as=A.size();
  reverse(A.begin(),A.end());
  reverse(B.begin(),B.end());
  A+='$';
  A+=B;
  Int N=A.size();
  vector<Int> ret=zalgorithm(A);
  for(Int i=as+1;i<N;i++){
    if(ret[i]+i==N){return ret[i];}
  }
  return 0;
}

Int period(const string &A){
  Int N=A.size();
  vector<Int> ret=zalgorithm(A);
  for(Int i=1;i<N;i++){
    if(ret[i]+i==N){return ret[i];}
  }
  return 0;
}

const Int INF=1e9;

signed main(){
  cin.tie(0);
  ios::sync_with_stdio(0);
  ll N;
  cin>>N;
  vector<string> A(N);
  for(auto &I:A){cin>>I;}
  PrimalDual<Int,Int> pd(2*N+2);
  Int s=2*N,g=s+1;
  for(Int i=0;i<N;i++){
    pd.add_edge(s,i,1,0);
    pd.add_edge(N+i,g,1,0);
    for(Int j=0;j<N;j++){
      if(i==j){
        pd.add_edge(i,N+j,1,INF-period(A[i]));
        //cout<<A[i]<<":"<<period(A[i])<<endl;
      }
      else{
        pd.add_edge(i,N+j,1,INF-same_str(A[i],A[j]));
        //cout<<A[i]<<" "<<A[j]<<":"<<same_str(A[i],A[j])<<endl;
      }
    }
  }
  Int ok=1;
  Int res=pd.flow(s,g,N,ok);
  Int sum=0;
  for(auto&I:A){sum+=I.size();}
  //  cout<<res<<endl;
  cout<<sum-(INF*N-res)<<endl;
  assert(ok);

  return 0;
}



Measured memory_bytes: 4024