You are given a graph with $n$ nodes and $m$ directed edges. One lowercase letter is assigned to each node. We define a path's value as the number of the most frequently occurring letter. For example, if letters on a path are "abaca", then the value of that path is $3$. Your task is find a path whose value is the largest.
The first line contains two positive integers $n, m$ ($1 \leq n, m \leq 300\,000$), denoting that the graph has $n$ nodes and $m$ directed edges.

The second line contains a string $s$ with only lowercase English letters. The $i$-th character is the letter assigned to the $i$-th node.

Then $m$ lines follow. Each line contains two integers $x, y$ ($1 \leq x, y \leq n$), describing a directed edge from $x$ to $y$. Note that $x$ can be equal to $y$ and there can be multiple edges between $x$ and $y$. Also the graph can be not connected.
In the first sample, the path with largest value is $1 \to 3 \to 4 \to 5$. The value is $3$ because the letter 'a' appears $3$ times.
5 4
abaca
1 2
1 3
3 4
4 5
3
6 6
xzyabc
1 2
3 1
2 3
5 4
4 3
6 4
-1
10 14
xzyzyzyzqx
1 2
2 4
3 5
4 5
2 6
6 8
6 5
2 10
3 9
10 9
4 6
1 10
2 8
3 7
4
1 1
f
1 1
-1
10 50
ebibwbjihv
1 10
1 2
5 4
1 8
9 7
5 6
1 8
8 7
2 6
5 4
1 9
3 2
8 3
5 6
5 9
2 4
2 7
3 9
1 2
1 7
1 10
3 7
1 8
3 10
8 6
1 7
10 6
1 6
5 8
1 5
2 10
3 9
5 8
8 3
3 7
5 2
1 10
1 4
5 3
3 2
1 2
5 8
10 4
2 10
8 2
1 9
1 8
1 2
3 4
1 8
2
13 37
dwpzcppjmhkmz
2 6
3 6
6 7
6 7
6 7
6 7
6 8
6 8
6 8
6 8
4 6
4 6
5 6
4 6
4 6
6 9
6 9
6 10
6 10
6 10
6 10
4 6
1 6
1 6
10 11
6 11
1 6
6 12
6 12
6 12
6 13
6 13
6 13
6 13
3 6
2 6
2 6
3
5 8
tetqw
2 1
4 4
5 5
5 2
4 5
1 5
1 5
1 1
-1
5 8
reeet
4 3
2 5
4 2
2 4
4 2
5 2
3 3
3 4
-1
"""THIS TEMPLATE belongs to anuj_negi"""

#Try to use bisect in case of binary search, bisect_left, bisect_right
#Try to use sortedcontainers when available
#Try to use Multiset when available
from bisect import *
from heapq import *
#from functools import cache, lru_cache
from math import *
from collections import defaultdict as ddc
from collections import Counter
from functools import *
from itertools import *
from sys import setrecursionlimit
import io,os

into = io.BytesIO(os.read(0,os.fstat(0).st_size)).readline
def input(): return into().decode().strip()

def intin(): return int(input())
def mapin(): return map(int, input().split())
def strin(): return input().split()   
def graphin(m):
    zz = ddc(set)
    for i in range(m):
        a, b = mapin()
        zz[a].add(b)
        
    return zz

#----------------------------------------------

INF = 1<<64     #Or use 10**20
mod = 10**9 + 7

#----------------------------------------------

"""
SOME FACTS THAT CAN BE USED LATER - 

-> if n is prime, then -> (a**(n-1)) % n = 1

-> When cases like DEFICIENT CITY to SURPLUS CITY, work on BFS using SURPLUS city and check for DEFICIENT city

-> PALINDROMEs and str-len FACTORS have some relations. if P = XQ where P, X, Q are palindromes, then X have the possible length in Factors of 'n'

-> When all substrings are said to be checked, we can go for 2 loops (With 100 limit of inner loop, minimize the memory)
"""

#----------------------------------------------
"""
-> THIS IS A Interval Based Segmented Trees
-> Can be modified or used later for similar
"""

class IntervalSeg:
    def __init__(self):
        self.Seg = ddc(int)
        self.otherAdded = ddc(int)
        
    def update(self, s, e, l = 0, r = 10**9, index = 1):
        if r<=s or e<=l: return
        if s<=l<r<=e:
            self.Seg[index]+=1
            self.otherAdded[index]+=1
            
        else:
            m = (l+r)//2
            self.update(s, e, l, m, 2*index)
            self.update(s, e, m, r, 2*index + 1)
            self.Seg[index] = self.otherAdded[index] + max(self.Seg[2*index], self.Seg[2*index + 1])
    
    def use(self, start, end):
        self.update(start, end)
        return self.Seg[1]

#----------------------------------------------
#FOR nCr
class nCr:
    def __init__(self):
            
        self.fact = [1]*(1000001)
        self.factinv = [1]*(1000001)
        for i in range(1, 1000001):
            self.fact[i] = self.fact[i-1] * i % mod
            
        self.factinv[-1] = exponentiation(self.fact[-1], mod-2, mod)
        for i in range(1000000-1, 1, -1):
            self.factinv[i] = self.factinv[i+1] * (i+1) % mod

    def C(self, n, r):
        if n<r or r<0: return 0
        return self.fact[n] * self.factinv[r] % mod * self.factinv[n-r] % mod


#----------------------------------------------
#Use this when really needed 
# Such as - Getting TLE because some TC can cause O(n^2) on pre-built HASHMAPS
def custom_hash(x):
    return x // 1000000007, x % 1000000007

#----------------------------------------------
#Subarray size - Rolling Hash - Custom
def hash_it(arr, size, mod = (10**9 + 7)):
    """
    mul -> must be greater than max(arr)
    rest can be modified
    """
    if not size: return 
    mul, hashh, div = 256, 0, (1<<(8*size-8))%mod
    
    C = ddc(list)
    for i in range(size):
        hashh = (mul * hashh + arr[i])%mod
    
    C[hashh].append(0)
    
    for i in range(len(arr)-size):
        #update the hashh
        hashh = (mul*(hashh-arr[i]*div) + arr[i+size])%mod
        C[hashh].append(i+1)
    
    return C

#----------------------------------------------

def LIS(arr, n):
    dp = [10**9]*(n+1)
        
    for ele in arr:
        dp[bisect_left(dp, ele)] = ele
    #print(dp)
    return bisect_left(dp, 10**9)

#----------------------------------------------
#Fast base^exp 
def exponentiation(bas, exp, mod = 10**9 + 7):
    t = 1
    while(exp > 0): 
  
        if (exp % 2 != 0):
            t = (t * bas) % mod
  
        bas = (bas * bas) % mod 
        exp //= 2
    return t % mod

#----------------------------------------------
#Fast multiplication
def fastMul(a, b, mod = 10**9 + 7):
    t = 0
    while(b > 0):   

        if (b % 2 != 0):
            t = (t + a) % mod

        a = (a + a) % mod 
        b //= 2
    return t % mod

#----------------------------------------------

#Returns P*Q^-1 % Mod
def modInv(p, q=1, mod = 10**9 + 7):
    expo = 0
    expo = mod - 2
 
    while (expo):
        if (expo & 1):
            p = (p * q) % mod
        q = (q * q) % mod
        expo >>= 1
    return p

#----------------------------------------------

def sortArrayMinSwap(arr, n):
    #O(nlogn)
    ans = 0
    Another = {ele:i for i, ele in enumerate(sorted(arr))}
    complete = [True]*n
    
    for j in range(n):
        i = j
        curr = 0
        while complete[i]:
            complete[i] = False
            i = Another[arr[i]]
            curr+=1
        
        if curr>0:
            ans += curr-1

    return ans

#----------------------------------------------

yes = "YES"
no = "NO"
even = "EVEN"
odd = "ODD"
alice = "ALICE"
bob = "BOB"

#----------------------------------------------

def process(arr, graph, n):
    indeg = ddc(int)
    dp = [[0]*26 for i in range(n)]
    vis = [False]*n
    chain = [False]*n
    for a in graph:
        for b in  graph[a]:
            indeg[b]+=1
    
    ans = [0]
    def dfs(u, p):
        vis[u-1] = True
        chain[u-1] = True
        for v in graph[u]:
            if v==p: continue
            if chain[v-1]:
                ans[0] = 1e9
                return
            if not vis[v-1]: 
                dfs(v, u)
            for i in range(26):
                dp[u-1][i] = max(dp[u-1][i], dp[v-1][i])
        
        dp[u-1][ord(arr[u-1])-97]+=1
        ans[0] = max(ans[0], dp[u-1][ord(arr[u-1])-97])
        chain[u-1] = False
    

    for i in range(n):
        if indeg[i+1]==0:
            dfs(i+1, -1)
    
    if ans[0]==1e9: return -1
    return ans[0]
        
        
def main():
    #T-testcases
    n, m = mapin()
    arr = input()
    graph = graphin(m)
    ans = process(arr, graph, n)
    print(ans)
    #print("Case #{0}: {1}".format(_+1, ans))
    
#--------------------------
if __name__ == "__main__":
    main()