#include <iostream>
#include <vector>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <map>
#include <set>
#include <tuple>
#include <bitset>
#include <memory>
#include <cmath>
#include <algorithm>
#include <functional>
#include <iomanip>
#include <numeric>
#include <climits>
#include <cfloat>
struct Edge {
	int to, cost; bool has_flow; Edge* pair{ nullptr };
};
int edit_distance(const std::string& a, const std::string& b) {
	std::vector<std::vector<int>> memo(2, std::vector<int>(a.size() + 1, 0));
	for (auto i = 0; i <= a.size(); ++i) memo[1][i] = i;
	for (auto i = 0; i < b.size(); ++i) {
		memo[i % 2][0] = memo[(i + 1) % 2][0] + 1;
		for (auto j = 0; j < a.size(); ++j) {
			if (a[j] == b[i]) {
				memo[i % 2][j + 1] = memo[(i + 1) % 2][j];
			}
			else {
				memo[i % 2][j + 1] = std::min({ memo[(i + 1) % 2][j] + 1, memo[i % 2][j] + 1, memo[(i + 1) % 2][j + 1] + 1 });
			}
		}
	}
	return memo[(b.size() + 1) % 2].back();
}
long long int min_cost_matching(std::vector<std::vector<Edge>> &node, const int source, const int sink) {
	std::vector<long long int> potential(node.size(), 0), min_cost(node.size(), 0);
	auto comparator = [](const std::pair<int, long long int>& a, const std::pair<int, long long int>& b) {return a.second > b.second; };
	std::priority_queue<std::pair<int, long long int>, std::vector<std::pair<int, long long int>>, decltype(comparator)> queue(comparator);
	std::vector<Edge*> prev_edge(node.size(), nullptr);
	long long int sum_cost = 0LL;
	while (true) {
		queue.emplace(source, 0LL);
		for (auto i = 0; i < min_cost.size(); ++i) min_cost[i] = LLONG_MAX;
		min_cost[source] = 0LL;
		while (!queue.empty()) {
			auto front = queue.top(); queue.pop();
			if (min_cost[front.first] == front.second && front.first != sink) {
				for (auto& next : node[front.first]) if (next.has_flow) {
					if (min_cost[next.to] > front.second + potential[front.first] + next.cost - potential[next.to]) {
						min_cost[next.to] = front.second + potential[front.first] + next.cost - potential[next.to];
						queue.emplace(next.to, min_cost[next.to]);
						prev_edge[next.to] = &(next);
					}
				}
			}
		}
		if (min_cost[sink] == LLONG_MAX) return sum_cost;
		for (auto i = 0; i < potential.size(); ++i) potential[i] += min_cost[i];
		sum_cost += potential[sink];
		auto last = sink;
		while (last != source) {
			prev_edge[last]->has_flow = false;
			prev_edge[last]->pair->has_flow = true;
			last = prev_edge[last]->pair->to;
		}
	}
	return sum_cost;
}
void add_edge(std::vector<std::vector<Edge>>& node, const int from, const int to, const int cost) {
	node[from].push_back(Edge{ to, cost, true });
	node[to].push_back(Edge{ from, -cost, false });
	node[from][node[from].size() - 1].pair = &node[to][node[to].size() - 1];
	node[to][node[to].size() - 1].pair = &node[from][node[from].size() - 1];
}
long long int cal_min_cost_translation(const std::vector<std::string>& from_words, const std::vector<std::pair<std::string, int>>& to_words) {
	std::vector<std::vector<Edge>> node(from_words.size() + to_words.size() + 2);
	const auto source = from_words.size() + to_words.size();
	const auto sink = source + 1;
	for (auto i = 0; i < from_words.size(); ++i) node[i].reserve(to_words.size() + 1);
	for (auto j = 0; j < to_words.size(); ++j) node[j + from_words.size()].reserve(from_words.size() + 1);
	node[source].reserve(from_words.size()); node[sink].reserve(to_words.size());
	for (auto i = 0; i < from_words.size(); ++i) {
		add_edge(node, source, i, 0);
		for (auto j = 0; j < to_words.size(); ++j) {
			const auto distance = edit_distance(from_words[i], to_words[j].first) * to_words[j].second;
			add_edge(node, i, j + from_words.size(), distance);
		}
	}
	for (auto i = 0; i < to_words.size(); ++i) add_edge(node, i + from_words.size(), sink, 0);
	return min_cost_matching(node, source, sink);
}
std::vector<std::string> split(std::string from, const char delimiter) {
	std::vector<std::string> result;
	auto left = 0;
	for (auto i = 0; i < from.size(); ++i) {
		if (from[i] == delimiter) {
			result.push_back(from.substr(left, i - left));
			left = i + 1;
		}
	}
	result.push_back(from.substr(left, from.size() - left));
	return result;
}
int main() {
	int n, m; std::cin >> n >> m; std::cin.ignore();
	std::map<std::string, int> map;
	for (auto i = 0; i < n; ++i) {
		std::string line; std::getline(std::cin, line);
		for (const auto& word : split(line, ' ')) {
			map[word]++;
		}
	}
	std::vector<std::pair<std::string, int>> to_words(map.size());
	std::copy(map.begin(), map.end(), to_words.begin());
	std::vector<std::string> from_words(m);
	for (auto& word : from_words) std::cin >> word;
	std::cout << cal_min_cost_translation(from_words, to_words) << std::endl;
}



Measured memory_bytes: 10584