#include<bits/stdc++.h>
#define Rep(i,a,b) for(register int i=(a);i<=(b);++i)
#define Repe(i,a,b) for(register int i=(a);i>=(b);--i)
#define pb push_back
#define mp make_pair
typedef unsigned long long uint64;
typedef unsigned int uint32;
typedef long long ll;
using namespace std;

namespace IO
{
    const uint32 Buffsize=1<<15,Output=1<<23;
    static char Ch[Buffsize],*S=Ch,*T=Ch;
    inline char getc()
	{
		return((S==T)&&(T=(S=Ch)+fread(Ch,1,Buffsize,stdin),S==T)?0:*S++);
	}
    static char Out[Output],*nowps=Out;
    
    inline void flush(){fwrite(Out,1,nowps-Out,stdout);nowps=Out;}

    template<typename T>inline void read(T&x)
	{
		x=0;static char ch;T f=1;
		for(ch=getc();!isdigit(ch);ch=getc())if(ch=='-')f=-1;
		for(;isdigit(ch);ch=getc())x=x*10+(ch^48);
		x*=f;
	}

	template<typename T>inline void write(T x,char ch='\n')
	{
		if(!x)*nowps++='0';
		if(x<0)*nowps++='-',x=-x;
		static uint32 sta[111],tp;
		for(tp=0;x;x/=10)sta[++tp]=x%10;
		for(;tp;*nowps++=sta[tp--]^48);
		*nowps++=ch;
	}
}
using IO::read;
using IO::write;
using IO::getc;
using IO::flush;

inline void Chkmin(int&u,int v){u>v?u=v:0;}

inline void Chkmax(int&u,int v){u<v?u=v:0;}

inline void file()
{
#ifndef ONLINE_JUDGE
	freopen("water.in","r",stdin);
	freopen("water.out","w",stdout);
#endif
}

const int MAXN=1e5+7;

static int n,P,a[MAXN],p[19][19];

inline void init()
{
	read(n),read(P);
	register char ch;
	while(!isalpha(ch=getc()));
	Rep(i,1,n)a[i]=ch,ch=getc();
	Rep(i,0,P-1)Rep(j,0,P-1)read(p[i][j]);
	Rep(i,0,P)p[P][i]=p[i][P]=1;
}

static int ans;

typedef pair<int,int>Pr;

set<Pr>G;

vector<int>shown[19];

bool vist[1<<20],has[MAXN];

inline int getpr(int ps)
{
	if(ps==1)return P;
	if(has[ps-1])return a[ps-1]-'a';
	static set<Pr>::iterator it;
	it=G.upper_bound(mp(ps,ps));
	if(it==G.begin())return P;
	--it;
	return a[it->second]-'a';
}

inline int getsf(int ps)
{
	if(ps==n)return P;
	if(has[ps+1])return a[ps+1]-'a';
	static set<Pr>::iterator it;
	it=G.upper_bound(mp(ps,ps));
	if(it==G.end())return P;
	return a[it->first]-'a';
}

inline void ins(int ps)
{
	has[ps]=1;
	int l=ps,r=ps;
	static set<Pr>::iterator it;
	if(has[ps-1]|has[ps+1])
	{
		it=G.upper_bound(mp(ps,ps));
		if(has[ps+1])r=it->second;
		if(has[ps-1])l=(--it)->first;
	}
	if(l!=ps)G.erase(it);
	if(r!=ps)G.erase(G.lower_bound(mp(ps,ps)));
	G.insert(mp(l,r));
}

inline void del(int ps)
{
	has[ps]=0;
	static set<Pr>::iterator it;
	it=G.upper_bound(mp(ps,ps)),--it;
	int l=it->first,r=it->second;
	G.erase(it);
	if(l^ps)G.insert(mp(l,ps-1));
	if(r^ps)G.insert(mp(ps+1,r));
}

void dfs(int now,int cnt)
{
	Chkmax(ans,cnt);
	Rep(i,0,P-1)if((~now>>i&1)&&!vist[now|1<<i])
	{
		int sz=shown[i].size()-1,fg=0;
		Rep(j,0,sz)if(!p[getpr(shown[i][j])][getsf(shown[i][j])])
		{fg=1;break;}
		if(fg)continue;
		Rep(j,0,sz)del(shown[i][j]);
		vist[now|1<<i]=1;
		dfs(now|1<<i,cnt+sz+1);
		if(ans==n)return;
		Rep(j,0,sz)ins(shown[i][j]);
	}
	if(ans==n)return;
}

inline void solve()
{
	register int e=0;
	Rep(i,1,n)if(a[i]!=a[i-1])a[++e]=a[i];
	n=e;
	Rep(i,1,n)has[i]=1;
	Rep(i,1,n)shown[a[i]-'a'].pb(i);
	G.insert(mp(1,n));
	int ft=0;
	Rep(i,0,P-1)if(!shown[i].size())ft|=1<<i;
	dfs(ft,0);
	cout<<n-ans<<endl;
}

int main()
{
    init();
    solve();
    return 0;
}
