#include    <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/rope>
#define fo(i,a,b) for(int i=(a);i<=(b);++i)
#define fd(i,a,b) for(int i=(a);i>=(b);--i)
#define rep(i,a,b)  for(int i=(a);i<(b);++i)
#define fore(i,a)  for(__typeof((a).begin()) i=(a).begin();i!=(a).end();++i)
#define __unique(V) (V).resize(unique((V).begin(),(V).end())-(V).begin())
#define cntbit(X)   __builtin_popcount((X))
#define bit(S,i) (((S)>>(i))&1)
#define PI	acos(-1)
#define fi  first
#define se  second
#define LL  long long
#define ii  pair<int,int>
#define iii pair<int,ii>
#define eb  emplace_back
#define TASK "1117F"
using namespace __gnu_pbds;
using namespace __gnu_cxx;
using namespace std;
typedef tree<ii,null_type,less<ii>,rb_tree_tag,
    tree_order_statistics_node_update> OST;
const int maxn = 1e5 + 5,maxP = (1 << 17) + 5;
int n,p,maxp,start,cnt[20],sum[maxn][20];
int nxt[maxn][20],a[maxn],adj[20][20];
int dp[maxP][20][20],dist[maxP];
///--------------------------
void    readf(){
    cin >> n >> p;
    maxp = (1 << p) - 1; p--;
    start = 0;
    fo(i,1,n){
        char ch;
        cin >> ch;
        a[i] = ch - 'a';
        fo(j,0,p) sum[i][j] = sum[i - 1][j];
        sum[i][a[i]]++;
        cnt[a[i]]++;
        start |= (1 << a[i]);
    }
    fo(i,0,p) fo(j,0,p) cin >> adj[i][j];
}
///--------------------------
int get(int u,int v,int ch){
    if (u > v) return 0;
    return sum[v][ch] - sum[u - 1][ch];
}
///--------------------------
bool    check(int mask){
    fo(i,0,p) fo(j,0,p) if (dp[mask][i][j] > adj[i][j]) return 0;
    return 1;
}
///--------------------------
int DFS(int mask){
    int &rs = dist[mask];
    if (rs != -1) return rs;
    if (!check(mask)) return (rs = -1e9);
    rs = 0;
    fo(i,0,p) if (bit(mask,i))
        rs = max(rs,cnt[i] + DFS(mask ^ (1 << i)));
    return rs;
}
///--------------------------
void    solve(){
    for(int i = n; i > 0; --i){
        fo(j,0,p) nxt[i][j] = nxt[i + 1][j];
        nxt[i][a[i]] = i;
    }
    for(int i = n; i > 0; --i){
        fo(j,0,p) if (nxt[i + 1][j]){
            if (get(i + 1,nxt[i + 1][j] - 1,a[i])
                || get(i + 1,nxt[i + 1][j] - 1,j)) continue;
            int mask = maxp;
            fo(k,0,p) if (get(i + 1,nxt[i + 1][j] - 1,k)){
                    mask ^= (1 << k);
            }
            dp[mask][a[i]][j] = dp[mask][j][a[i]] = 1;
        }
    }
    fo(i,1,p) for(int mask = maxp; mask >= 0; --mask) if (!bit(mask,i))
        fo(x,0,p) fo(y,0,p) if (bit(mask,x) && bit(mask,y))
            dp[mask][x][y] |= dp[mask ^ (1 << i)][x][y];
    memset(dist,-1,sizeof(dist));
    cout << n - DFS(start) << '\n';
}
///--------------------------
int     main(){
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    #ifndef ONLINE_JUDGE
        freopen(TASK".inp", "r", stdin);
        freopen(TASK".out", "w", stdout);
    #endif // ONLINE_JUDGE
    readf();
    solve();
}





