import java.lang.*; import java.util.*; import java.io.*; import static java.lang.Math.*; public class david { char[] str; int n, numv; Vector[][] edge; int subsets; Vector[] sub; char[] next = new char[256]; int ncomp, posorder; int[] comp; int[] order; david() { for (int i = 0; i < 4; ++i) next[alphabet.charAt(i)] = alphabet.charAt((i + 1) % 4); } void set(int i, int val) { int must = (2 * i) | val; edge[0][must ^ 1].add(must); } void add_or(int i, int v1, int j, int v2) { edge[0][(2 * i) | (v1 ^ 1)].add((2 * j) | v2); edge[0][(2 * j) | (v2 ^ 1)].add((2 * i) | v1); } void add_equal(int i, int j) { add_or(i, 1, j, 0); add_or(i, 0, j, 1); } void add_distinct(int i, int j) { add_or(i, 0, j, 0); add_or(i, 1, j, 1); } void dfs(int v, int e) { comp[v] = ncomp; for (int w: edge[e][v]) if (comp[w] < 0) dfs(w, e); if (e == 0) order[posorder++] = v; } String alphabet = new String("AGTC"); int dist(char a, char b) { int p = alphabet.indexOf(a), q = alphabet.indexOf(b), d = abs(p - q); return min(d, 4 - d); } boolean readInput(BufferedReader in) throws IOException { StringTokenizer st = new StringTokenizer(in.readLine()); n = Integer.parseInt(st.nextToken()); subsets = Integer.parseInt(st.nextToken()); if (n == 0) return false; str = in.readLine().toCharArray(); numv = 4 * n; edge = (Vector[][]) new Vector[2][numv]; for (int e = 0; e < 2; ++e) for (int i = 0; i < numv; ++i) edge[e][i] = new Vector(); comp = new int[numv]; order = new int[numv]; sub = (Vector[]) new Vector[subsets]; for (int s = 0; s < subsets; ++s) { sub[s] = new Vector(); st = new StringTokenizer(in.readLine(), " :"); int size = Integer.parseInt(st.nextToken()); for (int i = 0; i < size; ++i) sub[s].add(Integer.parseInt(st.nextToken())); } in.readLine(); return true; } void print(int a) { if (a % 2 == 0) System.out.print("not "); a /= 2; System.out.print(a < n ? "x" + a : "y" + (a - n)); } void print_graph() { for (int i = 0; i < numv; ++i) for (int k : edge[0][i]) { print(i); System.out.print(" => "); print(k); System.out.println(); } } void solve(PrintWriter out) { for (int i = 0; i < n - 1; ++i) add_or(i, 0, i + 1, 0); // not x_i or not x_{i+1} for (int s = 0; s < subsets; ++s) { for (int i = 0, j = sub[s].size() - 1; i < j; ++i, --j) { int a = sub[s].elementAt(i), b = sub[s].elementAt(j), d = dist(str[a], str[b]); if (d == 0) { add_equal(a, b); // x_i = x_j add_equal(a + n, b + n); // y_i = y_j } else if (d == 1) { add_distinct(a, b); // x_i != x_j int rev = (str[b] != next[str[a]]) ? 1 : 0; add_or(a, 1, b + n, rev); add_or(b, 1, a + n, rev ^ 1); } else { set(a, 1); set(b, 1); // x_i = x_j = 1 add_distinct(a + n, b + n); // y_i != y_j } } } // print_graph(); for (int i = 0; i < numv; ++i) for (int j: edge[0][i]) edge[1][j].add(i); Arrays.fill(comp, -1); ncomp = posorder = 0; for (int i = 0; i < numv; ++i) if (comp[i] < 0) { dfs(i, 0); ++ncomp; } Arrays.fill(comp, -1); ncomp = 0; for (int i = numv - 1; i >= 0; --i) if (comp[order[i]] < 0) { dfs(order[i], 1); ++ncomp; } boolean possible = true; for (int i = 0; possible && i < numv; i += 2) if (comp[i] == comp[i + 1]) possible = false; System.out.println(possible ? "YES" : "NO"); } public static void main(String[] args) { boolean first = true; try { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out)); for (;;) { david a = new david(); if (!a.readInput(in)) break; a.solve(out); } out.close(); } catch (Exception e) { e.printStackTrace(); } } }