One day, during daily web surfing, you encountered a web page which was written in a language you've never seen. The character set of the language was the same as your native language; moreover, the grammar and words seemed almost the same. Excitedly, you started to "decipher" the web page. The first approach you tried was to guess the meaning of each word by selecting a similar word from a dictionary of your native language. The closer two words (although from the different languages) are, the more similar meaning they will have.

You decided to adopt edit distance for the measurement of similarity between two words. The edit distance between two character sequences is defined as the minimum number of insertions, deletions and substitutions required to morph one sequence into the other. For example, the pair of "point" and "spoon" has the edit distance of 3: the latter can be obtained from the former by deleting 't', substituting 'i' to 'o', and finally inserting 's' at the beginning.

You wanted to assign a word in your language to each word in the web text so that the entire assignment has the minimum edit distance. The edit distance of an assignment is calculated as the total sum of edit distances between each word in the text and its counterpart in your language. Words appearing more than once in the text should be counted by the number of appearances.

The translation must be consistent across the entire text; you may not match different words from your dictionary for different occurrences of any word in the text. Similarly, different words in the text should not have the same meaning in your language.

Suppose the web page says "qwerty asdf zxcv" and your dictionary contains the words "qwert", "asf", "tyui", "zxcvb" and "ghjk". In this case, you can match the words in the page as follows, and the edit distance of this translation is 3: "qwert" for "qwerty", "asf" for "asdf" and "zxcvb" for "zxcv".

Write a program to calculate the minimum possible edit distance among all translations, for given a web page text and a word set in the dictionary.



Input

The first line of the input contains two integers N and M.

The following N lines represent the text from the web page you've found. This text contains only lowercase alphabets and white spaces. Then M lines, each containing a word, describe the dictionary to use. Every word consists of lowercase alphabets only, and does not contain more than 20 characters.

It is guaranteed that 1 ≤ N ≤ 100 and 1 ≤ M ≤ 400. Also it is guaranteed that the dictionary is made up of many enough words, which means the number of words in the dictionary is no less than the kinds of words in the text to translate. The length of each line in the text does not exceed 1000.

Output

Output the minimum possible edit distance in a line.

Example

Input

1 5
qwerty asdf zxcv
qwert
asf
tyui
zxcvb
ghjk


Output

3
#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 MAX 405
#define NUM 1005

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 V; //頂点数
vector<Edge> G[NUM]; //グラフの隣接リスト表現
int h[NUM]; //ポテンシャル
int dist[NUM]; //最短距離
int pre_node[NUM],pre_edge[NUM]; //直前の頂点と辺
int count_table[MAX];
int index_TEXT[MAX],index_word[MAX];
char line[1005],TEXT[MAX][21],words[MAX][21];
int dp[25][25];


//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 calc_dist(int text_index,int word_index){

	char A[21],B[21];
	int len_A,len_B;

	for(int k = 0; TEXT[text_index][k] != '\0'; k++){

		A[k] = TEXT[text_index][k];
		A[k+1] = '\0';
	}
	for(int k = 0; words[word_index][k] != '\0'; k++){

		B[k] = words[word_index][k];
		B[k+1] = '\0';
	}

	for(len_A = 0; A[len_A] != '\0'; len_A++);
	for(len_B = 0; B[len_B] != '\0'; len_B++);

	for(int row = 0; row <= len_A; row++){
		for(int col = 0; col <= len_B; col++){

			dp[row][col] = 0;
		}
	}

	for(int col = 0; col <= len_B; col++){
		dp[0][col] = col;
	}

	for(int row = 1; row <= len_A; row++){
		dp[row][0] = row;
	}

	int cost;

	for(int row = 1; row <= len_A; row++){
		for(int col = 1; col <= len_B; col++){
			if(B[col-1] == A[row-1]){
				cost = 0;
			}else{
				cost = 1;
			}
			dp[row][col] = min(dp[row-1][col-1]+cost,min(dp[row-1][col]+1,dp[row][col-1]+1));
		}
	}

	return dp[len_A][len_B];
}

bool strCmp(char* base, char* comp){
	int length1,length2;
	for(length1=0;base[length1] != '\0';length1++);
	for(length2=0;comp[length2] != '\0';length2++);
	if(length1 != length2)return false;

	for(int i=0;base[i] != '\0'; i++){
		if(base[i] != comp[i])return false;
	}
	return true;
}

void strcpy(char* to,char* str){
	for(int i=0;str[i] != '\0';i++){
		to[i] = str[i];
		to[i+1] = '\0';
	}
}

int main(){

	int N,M;
	scanf("%d %d",&N,&M);

	int num_text = 0;
	char work[21];

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

		count_table[i] = 0; //テキストの出現回数
	}

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

	getchar();

	for(int loop = 0; loop < N; loop++){

		fgets(line,2000,stdin);

		for(int i = 0; line[i] != '\0' && line[i] != '\n'; ){

			int k = 0;
			while(line[i+k] != '\0' && line[i+k] != '\n' && line[i+k] != ' '){

				work[k] = line[i+k];
				work[k+1] = '\0';
				k++;
			}

			bool FLG = false;
			for(int k = 0; k < num_text; k++){
				if(strCmp(work,TEXT[k])){

					count_table[k]++;
					FLG = true;
					break;
				}
			}
			if(!FLG){ //初登場

				strcpy(TEXT[num_text],work);
				count_table[num_text] = 1;
				index_TEXT[num_text] = index++;

				add_edge(source,index_TEXT[num_text],1,0);
				num_text++;
			}
			while(line[i+k] == ' ')k++;
			if(line[i+k] == '\0' || line[i+k] == '\n')break;

			i += k;
		}
	}

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

		scanf("%s",words[i]);
		index_word[i] = index++;
		add_edge(index_word[i],sink,1,0);
	}

	for(int from = 0; from < num_text; from++){

		for(int to = 0; to < M; to++){
			int tmp_dist = calc_dist(from,to);
			add_edge(index_TEXT[from],index_word[to],1,count_table[from]*tmp_dist);
		}
	}

	V = index;

	printf("%d\n", min_cost_flow(source,sink,num_text));

	return 0;
}

