#include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 99999999999999999
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;



#define SIZE 205
#define NUM 10000000

typedef pair<int,int> P; //firstは最短距離、secondは頂点の番号


//辺を表す構造体{行先、容量、コスト、逆辺のインデックス}
struct Edge{
	Edge(int arg_to,int arg_capacity,int arg_cost,int arg_rev_index){
		to = arg_to;
		capacity = arg_capacity;
		cost = arg_cost;
		rev_index = arg_rev_index;
	}

	int to,capacity,cost,rev_index;
};

int num_S;
int FROM[105],TO[105];
string S[105];

int V; //頂点数
vector<Edge> G[SIZE]; //グラフの隣接リスト表現
int h[SIZE]; //ポテンシャル
int dist[SIZE]; //最短距離
int pre_node[SIZE],pre_edge[SIZE]; //直前の頂点と辺
int z_algorithm[2005];


//文字列aの後ろに文字列bをくっつけた場合に、何文字重なるかを計算する関数
int calc_cover_length(int a,int b){

	string P = S[b] + '@' + S[a];
	int P_length = P.length();

	z_algorithm[0] = P_length;
	int index = 1,diff = 0,diff_2;

	while(index < P_length){
		while(index+diff < P_length && P[index+diff] == P[diff])diff++; //不一致箇所はP[diff]とP[index+diff]
		z_algorithm[index] = diff;

		if(diff == 0){ //1文字も一致しない場合
			index++;
			continue;
		}else{ //先頭からdiff文字一致したという事実を利用する

			diff_2 = 1;

			//一致長が[比較の先頭をずらした分だけ]減っていく間、以前の計算結果を再利用する
			while(index+diff_2 < P_length && z_algorithm[diff_2] < diff-diff_2){

				z_algorithm[index+diff_2] = z_algorithm[diff_2];
				diff_2++;
			}

			index += diff_2;
			diff -= diff_2;
		}
	}

	int start = S[b].length()+1;
	if(a == b){

		start++;
	}

	for(int i = start; i < P_length; i++){

		if(z_algorithm[i] == P_length-i){

			return z_algorithm[i];
		}
	}

	return 0;
}


//fromからtoへ向かう容量capacity,コストcostの辺をグラフに追加する
void add_edge(int from,int to,int capacity,int cost){
	G[from].push_back(Edge(to,capacity,cost,G[to].size()));
	G[to].push_back(Edge(from,0,-cost,G[from].size()-1));
}

//sourceからsinkへの、流量flowの最小費用流を求める
//流せない場合は-1を返す
int min_cost_flow(int source,int sink,int flow){
	int ret = 0;
	for(int i = 0; i < V; i++)h[i] = 0; //ポテンシャルを0にする
	while(flow > 0){
		//ダイクストラ法を用いてhを更新する
		priority_queue<P,vector<P>,greater<P>> Q;
		for(int i = 0; i < V; i++)dist[i] = BIG_NUM;
		dist[source] = 0;
		Q.push(P(0,source));

		while(!Q.empty()){
			P p = Q.top();
			Q.pop();
			int node_id = p.second;
			if(dist[node_id] < p.first)continue; //最短でなければSKIP
			for(int i = 0; i < G[node_id].size(); i++){
				Edge &e = G[node_id][i];
				if(e.capacity > 0 && dist[e.to] > dist[node_id]+e.cost+h[node_id]-h[e.to]){
					dist[e.to] = dist[node_id]+e.cost+h[node_id]-h[e.to];
					pre_node[e.to] = node_id;
					pre_edge[e.to] = i;
					Q.push(P(dist[e.to],e.to));
				}
			}
		}

		if(dist[sink] == BIG_NUM){
			//これ以上流せない
			return -1;
		}

		for(int node_id = 0; node_id < V; node_id++)h[node_id] += dist[node_id];

		//source-sink間最短路に沿って目いっぱい流す
		int tmp_flow = flow;
		for(int node_id = sink; node_id != source; node_id = pre_node[node_id]){
			tmp_flow = min(tmp_flow,G[pre_node[node_id]][pre_edge[node_id]].capacity);
		}
		flow -= tmp_flow;
		ret += tmp_flow*h[sink];
		for(int node_id = sink; node_id != source; node_id = pre_node[node_id]){
			Edge &e = G[pre_node[node_id]][pre_edge[node_id]];
			e.capacity -= tmp_flow;
			G[node_id][e.rev_index].capacity += tmp_flow;
		}
	}
	return ret;
}

int main(){

	scanf("%d",&num_S);

	int total_length = 0;

	for(int i = 0; i < num_S; i++){

		cin >> S[i];

		total_length += S[i].length();
	}

	int source = 0,sink = 1,index = 2;

	for(int i = 0; i < num_S; i++){

		FROM[i] = index++;
		add_edge(source,FROM[i],1,0);
	}

	for(int i = 0; i < num_S; i++){

		TO[i] = index++;
		add_edge(TO[i],sink,1,0);
	}

	for(int i = 0; i < num_S; i++){
		for(int k = 0; k < num_S; k++){

			add_edge(FROM[i],TO[k],1,NUM-calc_cover_length(i,k));
		}
	}

	V = index;

	int tmp = min_cost_flow(source,sink,num_S);

	tmp = NUM*num_S-tmp;

	printf("%d\n",total_length-tmp);

	return 0;
}



Measured memory_bytes: 3784