#include<bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;
using namespace std;
typedef long long ll;
typedef long double ld;

const int MAXN = 1e5+10;
int n, p;
string ss;
int s[MAXN];
int cnt[MAXN][26];
int A[26][26];

vector<int> occ[26];
gp_hash_table<int, null_type> forb;
gp_hash_table<int, null_type> vis;

bool contains(gp_hash_table<int, null_type> & v, int a) {
  return v.find(a) !=v.end();
}
void fkill(int f, int a, int b) {
  gp_hash_table<int, null_type> vis;
  if (contains(vis,f)) return; 
  vis.insert(f);
  forb.insert(f);
  queue<int> q;
  q.push(f);
  while(!q.empty()) {
    int f = q.front();
    q.pop();
    for(int i=0;i<p;i++) {
      if (i==a || i==b) continue;
      int nf = f | (1<<i);
      if (!contains(vis,nf)) {
        vis.insert(nf);
        forb.insert(nf);
        q.push(nf);
      }
    }
  }
}

int main(){
  cin.tie(0); ios_base::sync_with_stdio(0);
  cin >> n>> p >> ss;
  for(int i=0;i<p;i++) {
    for(int j=0;j<p;j++) {
      cin >> A[i][j];
    }
  }
  for(int i=1;i<=n;i++) {
    s[i] = ss[i-1] - 'a';
    for(int j=0;j<p;j++) {
      cnt[i][j] = cnt[i-1][j];
    }
    cnt[i][s[i]]++;
    occ[s[i]].push_back(i);
  }
  for(int a=0;a<p;a++) {
    // special case when a == a
    if (!A[a][a]) {
      vis.clear();
      int m = occ[a].size();
      for(int i=0;i<m-1;i++) {
        int l = occ[a][i];
        int r = occ[a][i+1];
        int f = 0;
        for(int j=0;j<p;j++) {
          int cj = cnt[r-1][j] - cnt[l][j];
          if (cj) f |= (1<<j);
        }
        //cerr << " BAD " << bitset<10> (f) << " " <<a << " " << a << " " << l << " " << r <<endl;
        fkill(f, a, a);
      }
    }
    // otherwise
    for(int b=a+1;b<p;b++) {
      if (A[a][b]) continue;
      vis.clear();
      // two pointer walk
      vector<pair<int,int>> v;
      for(int i: occ[a]) v.emplace_back(i, 1);
      for(int i: occ[b]) v.emplace_back(i, -1);
      sort(v.begin(), v.end());
      int m = v.size();
      for(int i=0;i<m-1;i++) {
        if (v[i].second == v[i+1].second) continue;
        int l = v[i].first;
        int r = v[i+1].first;
        int f = 0;
        for(int j=0;j<p;j++) {
          int cj = cnt[r-1][j] - cnt[l][j];
          if (cj) f |= (1<<j);
        }
        //cerr << " BAD " << bitset<10> (f) << " " <<a << " " << b <<endl;
        fkill(f, a, b);
      }
    }
  }
  //cerr << "BEFORE " << endl; for(auto f: forb) cerr << bitset<10>(f) <<endl; cerr << "AFTER" <<endl;
//  for(auto f: forb) cerr << bitset<5>(f) <<endl;

  queue<int> q;
  q.push(0);
  vis.insert(0);
  vis.clear();
  int best = n;
  while(!q.empty()) {
    int f = q.front();
    //cerr << "@ " << bitset<5>(f) <<endl;
    q.pop();
    int st = n;
    for(int i=0;i<p;i++) {
      if (f>>i&1) st-= (int)occ[i].size();
    }
    best = min(best, st);
    for(int i=0;i<p;i++) {
      int nf = f | (1<<i);
      if (!contains(forb,nf) && !contains(vis,nf)) {
        q.push(nf);
        vis.insert(nf);
      }
    }
  }
  cerr << best <<endl;
}
