#include <cstdio>
#include <vector>
#include <algorithm>
#include <utility>
#include <queue>
#include <cctype>
using namespace std;

typedef long long LL;

struct field{
	vector<char> ch;
	vector<vector<char> > con;
	vector<LL> st;
	
	int V;
	vector<char> used;
	vector<int> vs, cmp;
	vector<vector<int> > G, rG;
	
	field(){}
	field(int n, const vector<char> &ch)
	: V(n), used(n), cmp(n), G(n), rG(n), ch(ch)
	{ }
	
	void add_edge(int a, int b){
		G[a].push_back(b);
		rG[b].push_back(a);
	}
	
	void dfs(int v){
		used[v] = 1;
		for(int i = 0; i < G[v].size(); ++i){
			if(!used[G[v][i]]){ dfs(G[v][i]); }
		}
		vs.push_back(v);
	}
	
	void rdfs(int v, int k){
		used[v] = 1;
		cmp[v] = k;
		for(int i = 0; i < rG[v].size(); ++i){
			if(!used[rG[v][i]]){ rdfs(rG[v][i], k); }
		}
	}
	
	int scc(){
		fill(used.begin(), used.end(), 0);
		vs.clear();
		for(int v = 0; v < V; ++v){
			if(!used[v]){ dfs(v); }
		}
		fill(used.begin(), used.end(), 0);
		int k = 0;
		for(int i = vs.size() - 1; i >= 0; --i){
			if(!used[vs[i]]){ rdfs(vs[i], k++); }
		}
		return k;
	}
};


int solve(){
	field fld[2];
	int sc[2];
	for(int i = 0; i < 2; ++i){
		field &f = fld[i];
	
		int n, m, a, b;
		scanf("%d%d", &n, &m);
		vector<char> ch(n);
		for(int j = 0; j < n; ++j){
			scanf(" %c", &ch[j]);
		}
		
		f = field(n, ch);
		for(int j = 0; j < m; ++j){
			scanf("%d%d", &a, &b);
			f.add_edge(a - 1, b - 1);
		}

		sc[i] = f.scc();

		f.con.assign(sc[i], vector<char>(sc[i]));
		f.st.resize(sc[i]);

		for(int j = 0; j < n; ++j){
			a = f.cmp[j];
			for(int k = 0; k < f.G[j].size(); ++k){
				b = f.cmp[f.G[j][k]];
				f.con[a][b] = 1;
			}

			char c = f.ch[j];
			int k = isupper(c) ? c - 'A' : c - 'a' + 26;
			f.st[a] |= 1LL << k;
		}
	}

	vector<vector<int> > refcnt(sc[0], vector<int>(sc[1]));
	vector<vector<int> > d = refcnt;

	for(int i = 0; i < sc[0]; ++i)
	for(int j = 0; j < sc[1]; ++j){
		LL x = fld[0].st[i], y = fld[1].st[j];
		if(x & y){
			if(fld[0].con[i][i] && fld[1].con[j][j]){
				return -1;
			}

			for(int t = 0; t < sc[0]; ++t)
			for(int u = 0; u < sc[1]; ++u){
				if(fld[0].con[i][t] && fld[1].con[j][u]){
					++refcnt[t][u];
				}
			}
		}
		else{
			for(int t = 0; t < sc[0]; ++t){
				if(fld[0].con[i][t] && i != t){
					++refcnt[t][j];
				}
			}
			for(int u = 0; u < sc[1]; ++u){
				if(fld[1].con[j][u] && j != u){
					++refcnt[i][u];
				}
			}
		}
	}
	
	queue<int> q;
	for(int i = 0; i < sc[0]; ++i)
	for(int j = 0; j < sc[1]; ++j){
		if(refcnt[i][j] == 0){
			q.push(i << 8 | j);
		}
	}

	while(!q.empty()){
		int a = q.front() >> 8, b = q.front() & 0xff;
		q.pop();

		if(fld[0].st[a] & fld[1].st[b]){
			++d[a][b];
			for(int t = 0; t < sc[0]; ++t)
			for(int u = 0; u < sc[1]; ++u){
				if(fld[0].con[a][t] && fld[1].con[b][u]){
					d[t][u] = max(d[t][u], d[a][b]);
					if(--refcnt[t][u] == 0){
						q.push(t << 8 | u);
					}
				}
			}
		}
		else{
			for(int t = 0; t < sc[0]; ++t){
				if(fld[0].con[a][t]){
					d[t][b] = max(d[t][b], d[a][b]);
					if(--refcnt[t][b] == 0){
						q.push(t << 8 | b);
					}
				}
			}
			for(int u = 0; u < sc[1]; ++u){
				if(fld[1].con[b][u]){
					d[a][u] = max(d[a][u], d[a][b]);
					if(--refcnt[a][u] == 0){
						q.push(a << 8 | u);
					}
				}
			}
		}
	}
	
	int ans = 0;
	for(int i = 0; i < sc[0]; ++i){
		ans = max(ans, *max_element(d[i].begin(), d[i].end()));
	}
	return ans;
}

int main(){
	printf("%d\n", solve());
}

Measured memory_bytes: 1320