#include <bits/stdc++.h>
using namespace std;
#pragma GCC optimize("Ofast")
typedef vector<int> vi;
typedef long long lint;
typedef unsigned int uint;
typedef pair<int, int> pii;
typedef pair<lint, lint> pll;
typedef unsigned long long ulint;
#define endl '\n'
#define fst first
#define sed second
#define pb push_back
#define mp make_pair
#define rint register int
#define SZ(x) (int((x).size()))
#define all(x) (x).begin(), (x).end()
#define reveal(x) cerr << #x << " = " << (x) << endl
#define rep(it, f, e) for (rint it = (f); it <= (e); ++it)
#define per(it, f, e) for (rint it = (f); it >= (e); --it)
#define repe(it, x) for (auto it = (x).begin(); it != (x).end(); ++it)
const int MAXN = 1e5 + 20;
int s[MAXN];
vector<int> pos[20];
int ban2[1 << 18];
int cnt[20], ban[1 << 18];
int las[20], nex[MAXN][20];
int mat[20][20], dp[1 << 18];
int msk[MAXN][22], log_2[MAXN];
inline void buildST(int n) {
	rep (x, 1, 21) {
		int len = 1 << x;
		for (int i = 1; i + len - 1 <= n; ++i) {
			msk[i][x] = msk[i][x - 1] | msk[i + len / 2][x - 1];
		}
	}
}
inline int query(int l, int r) {
	int vp = log_2[r - l + 1];
	int res = msk[l][vp] | msk[r - (1 << vp) + 1][vp];
	if (res >> s[l] & 1) res ^= 1 << s[l];
	if (res >> s[r] & 1) res ^= 1 << s[r];
	return res;
}
inline void dfs(int mask) {
	if (ban[mask]) return;
	ban[mask] = 1;
	for (int p = mask; p; p -= p & (-p)) {
		dfs(mask ^ (p & (-p)));
	}
}
int res = MAXN, n, p;
inline void solve(int mask, int tot) {
	if (dp[mask]) return;
	if (ban2[mask]) return;
	res = min(res, n - tot);
	rep (i, 0, p - 1) if (mask >> i & 1) {
		solve(mask ^ (1 << i), tot + cnt[i]);
	}
}
int main() {
	ios::sync_with_stdio(false);
	cin.tie(NULL), cout.tie(NULL);
	rep (i, 3, MAXN - 1) {
		log_2[i] = log_2[i >> 1] + 1;
	}
	cin >> n >> p;
	rep (i, 1, n) {
		char ch;
		cin >> ch;
		++cnt[s[i] = ch - 'a'];
		msk[i][0] = 1 << s[i];
	}
	buildST(n);
	per (i, n, 1) {
		memcpy(nex[i], las, sizeof(las));
		las[s[i]] = i, pos[s[i]].push_back(i);
	}
	rep (i, 0, p - 1) {
		rep (j, 0, p - 1) {
			cin >> mat[i][j];
		}
	}
	rep (i, 0, p - 1) {
		rep (j, 0, p - 1) if (!mat[i][j]) {
			memset(ban, 0, sizeof(ban));
			for (auto x : pos[i]) if (nex[x][j]) {
				if ((nex[x][i] >= nex[x][j] || nex[x][i] == 0)) {
					dfs(((1 << p) - 1) ^ query(x, nex[x][j]));
				}
			}
			int orr = 1 << i | 1 << j;
			rep (mask, 0, (1 << p) - 1) {
				if ((mask & orr) == orr) ban2[mask] |= ban[mask];
			}
		}
	}
	solve((1 << p) - 1, 0);
	cout << res << endl;
	return 0;
}