In Isart people don't die. There are n gangs of criminals. The i-th gang contains si evil people numerated from 0 to si - 1. Some of these people took part in a big mine robbery and picked one gold bullion each (these people are given in the input). That happened 10100 years ago and then all of the gangs escaped to a remote area, far from towns.During the years, they were copying some gold bullions according to an organized plan in order to not get arrested. They constructed a tournament directed graph (a graph where there is exactly one directed edge between every pair of vertices) of gangs (the graph is given in the input). In this graph an edge from u to v means that in the i-th hour the person  of the gang u can send a fake gold bullion to person  of gang v. He sends it if he has some bullion (real or fake), while the receiver doesn't have any. Thus, at any moment each of the gangsters has zero or one gold bullion. Some of them have real bullions, and some of them have fake ones.In the beginning of this year, the police has finally found the gangs, but they couldn't catch them, as usual. The police decided to open a jewelry store so that the gangsters would sell the bullions. Thus, every gangster that has a bullion (fake or real) will try to sell it. If he has a real gold bullion, he sells it without problems, but if he has a fake one, there is a choice of two events that can happen:   The person sells the gold bullion successfully.  The person is arrested by police. The power of a gang is the number of people in it that successfully sold their bullion. After all selling is done, the police arrests b gangs out of top gangs. Sort the gangs by powers, we call the first a gang top gangs(you can sort the equal powers in each order). Consider all possible results of selling fake gold bullions and all possible choice of b gangs among the top gangs. Count the number of different sets of these b gangs modulo 109 + 7. Two sets X and Y are considered different if some gang is in X and isn't in Y.

The first line contains four integers n, a and b (1 ≤ b ≤ a ≤ n ≤ 5·103) — the number of gangs, the constants a and b from the statement. Then n lines follow, each line contains a string of size n consisting of zeros and ones. The j-th character in the i-th of these lines is equal to 1, then the vertex i have a directed edge to the vertex j. It is guaranteed that aii = 0 and aij + aji = 1 if i ≠ j. Then n lines follow, each line starts with the integer si (1 ≤ si ≤ 2·106) — the number of gangsters in the i-th gang, and then contains a string of zeros and ones with length si. The j-th character is 0 if the j-th person of the i-th gang had a real gold bullion initially, otherwise it is 1. It is guaranteed that the sum of si does not exceed 2·106.

Print single integer: the number of different sets of b gangs the police can arrest modulo 109 + 7.

import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.BufferedWriter;
import java.util.InputMismatchException;
import java.io.IOException;
import java.util.Stack;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
import java.util.Vector;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.util.BitSet;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual  solution is at the top
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        OutputWriter out = new OutputWriter(outputStream);
        TaskF solver = new TaskF();
        solver.solve(1, in, out);
        out.close();
    }

    static class TaskF {
        public int mod = 1000000007;
        public int n;
        public int a;
        public int b;
        public char[][] adj;
        public List<Integer>[] graph;

        public void solve(int testNumber, InputReader in, OutputWriter out) {
            n = in.nextInt();
            a = in.nextInt();
            b = in.nextInt();
            adj = new char[n][n];
            graph = Stream.generate(ArrayList::new).limit(n).toArray(List[]::new);
            for (int i = 0; i < n; i++) adj[i] = in.next().toCharArray();
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < n; j++) {
                    if (adj[i][j] == '1') {
                        graph[i].add(j);
                    }
                }
            }
            List<List<Integer>> comp = new SCCTarjan().scc(graph);
            boolean[][] can = new boolean[n][];
            int[] low = new int[n];
            for (int i = 0; i < n; i++) {
                int q = in.nextInt();
                char[] w = in.next().toCharArray();
                can[i] = new boolean[q];
                for (int j = 0; j < q; j++) {
                    can[i][j] = w[j] == '1';
                    if (can[i][j]) low[i]++;
                }
            }
            int[] wcomp = new int[n];
            int idx = 0;
            List<BitSet> bb = new ArrayList<>();
            List<Integer> bs = new ArrayList<>();
            for (List<Integer> gg : comp) {
                int gcd = 0;
                for (int x : gg) {
                    gcd = Utils.gcd(gcd, can[x].length);
                    wcomp[x] = idx;
                }
                idx++;
                BitSet d = new BitSet(gcd);
                bs.add(gcd);
                bb.add(d);
                for (int x : gg) {
                    for (int i = 0; i < can[x].length; i++) {
                        if (can[x][i]) {
                            d.set(i % gcd, true);
                        }
                    }
                }
            }

            for (int kk = comp.size() - 1; kk > 0; kk--) {
                int g = Utils.gcd(bs.get(kk), bs.get(kk - 1));
                BitSet ww = new BitSet(g);
                for (int i = 0; i < bs.get(kk); i += g) {
                    ww.or(bb.get(kk).get(i, i + g));
                }
                for (int i = 0; i < bs.get(kk - 1); i++) {
                    if (ww.get(i % g)) {
                        bb.get(kk - 1).set(i, true);
                    }
                }
            }
            int[] high = new int[n];
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < can[i].length; j++) {
                    if (bb.get(wcomp[i]).get(j % bs.get(wcomp[i])))
                        high[i]++;
                }
            }
            long ret = 0;
            int[][] comb = Utils.getComb(n + 1, mod);
            for (int lowest = 0; lowest < n; lowest++) {
                int countabove = 0;
                for (int other = 0; other < n; other++) {
                    if (other == lowest) continue;
                    if (low[other] > high[lowest]) {
                        countabove++;
                    }
                }
                if (countabove >= a) {
                    continue;
                }
                int canbig = 0;
                for (int other = 0; other < n; other++) {
                    if (other == lowest) continue;
                    if (low[other] <= high[lowest] && (high[other] > high[lowest] || (high[other] == high[lowest] && other > lowest))) {
                        canbig++;
                    }
                }

                for (int take = 0; take < b && take <= canbig && take + countabove < a; take++) {
                    ret = (ret + 1L * comb[canbig][take] * comb[countabove][b - take - 1]) % mod;
                }
            }
            out.println(ret);
        }

    }

    static class OutputWriter {
        private final PrintWriter writer;

        public OutputWriter(OutputStream outputStream) {
            writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream)));
        }

        public OutputWriter(Writer writer) {
            this.writer = new PrintWriter(writer);
        }

        public void close() {
            writer.close();
        }

        public void println(long i) {
            writer.println(i);
        }

    }

    static class Utils {
        public static int gcd(int a, int b) {
            return b == 0 ? a : gcd(b, a % b);
        }

        public static int[][] getComb(int sz, int mod) {
            int[][] comb = new int[sz][sz];
            for (int i = 0; i < sz; i++) {
                comb[i][0] = 1;
                for (int j = 1; j <= i; j++) {
                    comb[i][j] = comb[i - 1][j] + comb[i - 1][j - 1];
                    if (comb[i][j] >= mod) comb[i][j] -= mod;
                }
            }
            return comb;
        }

    }

    static class InputReader {
        private InputStream stream;
        private byte[] buf = new byte[1024];
        private int curChar;
        private int numChars;

        public InputReader(InputStream stream) {
            this.stream = stream;
        }

        public int read() {
            if (this.numChars == -1) {
                throw new InputMismatchException();
            } else {
                if (this.curChar >= this.numChars) {
                    this.curChar = 0;

                    try {
                        this.numChars = this.stream.read(this.buf);
                    } catch (IOException var2) {
                        throw new InputMismatchException();
                    }

                    if (this.numChars <= 0) {
                        return -1;
                    }
                }

                return this.buf[this.curChar++];
            }
        }

        public int nextInt() {
            int c;
            for (c = this.read(); isSpaceChar(c); c = this.read()) {
                ;
            }

            byte sgn = 1;
            if (c == 45) {
                sgn = -1;
                c = this.read();
            }

            int res = 0;

            while (c >= 48 && c <= 57) {
                res *= 10;
                res += c - 48;
                c = this.read();
                if (isSpaceChar(c)) {
                    return res * sgn;
                }
            }

            throw new InputMismatchException();
        }

        public String next() {
            int c;
            while (isSpaceChar(c = this.read())) {
                ;
            }

            StringBuilder result = new StringBuilder();
            result.appendCodePoint(c);

            while (!isSpaceChar(c = this.read())) {
                result.appendCodePoint(c);
            }

            return result.toString();
        }

        public static boolean isSpaceChar(int c) {
            return c == 32 || c == 10 || c == 13 || c == 9 || c == -1;
        }

    }

    static class SCCTarjan {
        List<Integer>[] graph;
        boolean[] visited;
        Stack<Integer> stack;
        int time;
        int[] lowlink;
        List<List<Integer>> components;

        public List<List<Integer>> scc(List<Integer>[] graph) {
            int n = graph.length;
            this.graph = graph;
            visited = new boolean[n];
            stack = new Stack<>();
            time = 0;
            lowlink = new int[n];
            components = new ArrayList<>();

            for (int u = 0; u < n; u++)
                if (!visited[u])
                    dfs(u);

            return components;
        }

        void dfs(int u) {
            lowlink[u] = time++;
            visited[u] = true;
            stack.add(u);
            boolean isComponentRoot = true;

            for (int v : graph[u]) {
                if (!visited[v])
                    dfs(v);
                if (lowlink[u] > lowlink[v]) {
                    lowlink[u] = lowlink[v];
                    isComponentRoot = false;
                }
            }

            if (isComponentRoot) {
                List<Integer> component = new ArrayList<>();
                while (true) {
                    int x = stack.pop();
                    component.add(x);
                    lowlink[x] = Integer.MAX_VALUE;
                    if (x == u)
                        break;
                }
                components.add(component);
            }
        }

    }
}

import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.BufferedWriter;
import java.util.InputMismatchException;
import java.io.IOException;
import java.util.Stack;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
import java.util.Vector;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.util.BitSet;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        OutputWriter out = new OutputWriter(outputStream);
        TaskF solver = new TaskF();
        solver.solve(1, in, out);
        out.close();
    }

    static class TaskF {
        public int mod = 1000000007;
        public int n;
        public int a;
        public int b;
        public char[][] adj;
        public List<Integer>[] graph;

        public void solve(int testNumber, InputReader in, OutputWriter out) {
            n = in.nextInt();
            a = in.nextInt();
            b = in.nextInt();
            adj = new char[n][n];
            graph = Stream.generate(ArrayList::new).limit(n).toArray(List[]::new);
            for (int i = 0; i < n; i++) adj[i] = in.next().toCharArray();
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < n; j++) {
                    if (adj[i][j] == '1') {
                        graph[i].add(j);
                    }
                }
            }
            List<List<Integer>> comp = new SCCTarjan().scc(graph);
            boolean[][] can = new boolean[n][];
            int[] low = new int[n];
            for (int i = 0; i < n; i++) {
                int q = in.nextInt();
                char[] w = in.next().toCharArray();
                can[i] = new boolean[q];
                for (int j = 0; j < q; j++) {
                    can[i][j] = w[j] == '1';
                    if (can[i][j]) low[i]++;
                }
            }
            int[] wcomp = new int[n];
            int idx = 0;
            List<BitSet> bb = new ArrayList<>();
            List<Integer> bs = new ArrayList<>();
            for (List<Integer> gg : comp) {
                int gcd = 0;
                for (int x : gg) {
                    gcd = Utils.gcd(gcd, can[x].length);
                    wcomp[x] = idx;
                }
                idx++;
                BitSet d = new BitSet(gcd);
                bs.add(gcd);
                bb.add(d);
                for (int x : gg) {
                    for (int i = 0; i < can[x].length; i++) {
                        if (can[x][i]) {
                            d.set(i % gcd, true);
                        }
                    }
                }
            }

            for (int kk = comp.size() - 1; kk >= 0; kk--) {
                List<Integer> gg = comp.get(kk);
                for (int x : gg) {
                    for (int y : graph[x]) {
                        if (wcomp[y] == wcomp[x] - 1) {
                            int g = Utils.gcd(bs.get(wcomp[x]), bs.get(wcomp[y]));
                            BitSet ww = new BitSet(g);
                            for (int i = 0; i < bs.get(wcomp[x]); i += g) {
                                ww.or(bb.get(wcomp[x]).get(i, i + g));
                            }
                            for (int i = 0; i < bs.get(wcomp[y]); i++) {
                                if (ww.get(i % g)) {
                                    bb.get(wcomp[y]).set(i, true);
                                }
                            }
                            break;
                        }
                    }
                }
            }
            int[] high = new int[n];
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < can[i].length; j++) {
                    if (bb.get(wcomp[i]).get(j % bs.get(wcomp[i])))
                        high[i]++;
                }
            }
            long ret = 0;
            int[][] comb = Utils.getComb(n + 1, mod);
            for (int lowest = 0; lowest < n; lowest++) {
                int countabove = 0;
                for (int other = 0; other < n; other++) {
                    if (other == lowest) continue;
                    if (low[other] > high[lowest]) {
                        countabove++;
                    }
                }
                if (countabove >= a) {
                    continue;
                }
                int canbig = 0;
                for (int other = 0; other < n; other++) {
                    if (other == lowest) continue;
                    if (low[other] <= high[lowest] && (high[other] > high[lowest] || (high[other] == high[lowest] && other > lowest))) {
                        canbig++;
                    }
                }

                for (int take = 0; take < b && take <= canbig && take + countabove < a; take++) {
                    ret = (ret + 1L * comb[canbig][take] * comb[countabove][b - take - 1]) % mod;
                }
            }
            out.println(ret);
        }

    }

    static class OutputWriter {
        private final PrintWriter writer;

        public OutputWriter(OutputStream outputStream) {
            writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream)));
        }

        public OutputWriter(Writer writer) {
            this.writer = new PrintWriter(writer);
        }

        public void close() {
            writer.close();
        }

        public void println(long i) {
            writer.println(i);
        }

    }

    static class Utils {
        public static int gcd(int a, int b) {
            return b == 0 ? a : gcd(b, a % b);
        }

        public static int[][] getComb(int sz, int mod) {
            int[][] comb = new int[sz][sz];
            for (int i = 0; i < sz; i++) {
                comb[i][0] = 1;
                for (int j = 1; j <= i; j++) {
                    comb[i][j] = comb[i - 1][j] + comb[i - 1][j - 1];
                    if (comb[i][j] >= mod) comb[i][j] -= mod;
                }
            }
            return comb;
        }

    }

    static class InputReader {
        private InputStream stream;
        private byte[] buf = new byte[1024];
        private int curChar;
        private int numChars;

        public InputReader(InputStream stream) {
            this.stream = stream;
        }

        public int read() {
            if (this.numChars == -1) {
                throw new InputMismatchException();
            } else {
                if (this.curChar >= this.numChars) {
                    this.curChar = 0;

                    try {
                        this.numChars = this.stream.read(this.buf);
                    } catch (IOException var2) {
                        throw new InputMismatchException();
                    }

                    if (this.numChars <= 0) {
                        return -1;
                    }
                }

                return this.buf[this.curChar++];
            }
        }

        public int nextInt() {
            int c;
            for (c = this.read(); isSpaceChar(c); c = this.read()) {
                ;
            }

            byte sgn = 1;
            if (c == 45) {
                sgn = -1;
                c = this.read();
            }

            int res = 0;

            while (c >= 48 && c <= 57) {
                res *= 10;
                res += c - 48;
                c = this.read();
                if (isSpaceChar(c)) {
                    return res * sgn;
                }
            }

            throw new InputMismatchException();
        }

        public String next() {
            int c;
            while (isSpaceChar(c = this.read())) {
                ;
            }

            StringBuilder result = new StringBuilder();
            result.appendCodePoint(c);

            while (!isSpaceChar(c = this.read())) {
                result.appendCodePoint(c);
            }

            return result.toString();
        }

        public static boolean isSpaceChar(int c) {
            return c == 32 || c == 10 || c == 13 || c == 9 || c == -1;
        }

    }

    static class SCCTarjan {
        List<Integer>[] graph;
        boolean[] visited;
        Stack<Integer> stack;
        int time;
        int[] lowlink;
        List<List<Integer>> components;

        public List<List<Integer>> scc(List<Integer>[] graph) {
            int n = graph.length;
            this.graph = graph;
            visited = new boolean[n];
            stack = new Stack<>();
            time = 0;
            lowlink = new int[n];
            components = new ArrayList<>();

            for (int u = 0; u < n; u++)
                if (!visited[u])
                    dfs(u);

            return components;
        }

        void dfs(int u) {
            lowlink[u] = time++;
            visited[u] = true;
            stack.add(u);
            boolean isComponentRoot = true;

            for (int v : graph[u]) {
                if (!visited[v])
                    dfs(v);
                if (lowlink[u] > lowlink[v]) {
                    lowlink[u] = lowlink[v];
                    isComponentRoot = false;
                }
            }

            if (isComponentRoot) {
                List<Integer> component = new ArrayList<>();
                while (true) {
                    int x = stack.pop();
                    component.add(x);
                    lowlink[x] = Integer.MAX_VALUE;
                    if (x == u)
                        break;
                }
                components.add(component);
            }
        }

    }
}

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.StringTokenizer;

public class Div1_411F {

	int numTV;
	int A;
	int B;

	ArrayList<Integer>[] tAList;

	boolean[][] tVAct;
	int[] numM;

	int cTime = 0;
	int[] disc;
	int[] low;

	ArrayDeque<Integer> stack = new ArrayDeque<Integer>();

	ArrayList<ArrayList<Integer>> sCCs = new ArrayList<ArrayList<Integer>>();

	int numC;

	boolean[][] compAct;

	// represents the minimum and the maximum amounts of active members a tournament vertex can have
	int[] min;
	int[] max;

	long MOD = 1_000_000_007L;

	int[][] comb;

	void dfs(int cV) {
		disc[cV] = low[cV] = cTime++;
		stack.push(cV);

		for (int adj : tAList[cV]) {
			if (disc[adj] == -1) {
				dfs(adj);
			}
			if (low[adj] < low[cV]) {
				low[cV] = low[adj];
			}
		}
		if (disc[cV] == low[cV]) {
			ArrayList<Integer> cSCC = new ArrayList<Integer>();
			while (stack.peek() != cV) {
				low[stack.peek()] = Integer.MAX_VALUE;
				cSCC.add(stack.pop());
			}
			low[stack.pop()] = Integer.MAX_VALUE;
			cSCC.add(cV);
			sCCs.add(cSCC);
		}
	}

	void findSCCs() {
		disc = new int[numTV];
		low = new int[numTV];
		Arrays.fill(disc, -1);

		for (int i = 0; i < numTV; i++) {
			if (disc[i] == -1) {
				dfs(i);
			}
		}

		numC = sCCs.size();
	}

	int fGCD(int a, int b) {
		while (b != 0) {
			int t = b;
			b = a % b;
			a = t;
		}
		return a;
	}

	void condenseComps() {
		compAct = new boolean[numC][];
		for (int cComp = 0; cComp < numC; cComp++) {
			ArrayList<Integer> cMems = sCCs.get(cComp);
			int cGCD = numM[cMems.get(0)];
			for (int j : cMems) {
				cGCD = fGCD(cGCD, numM[j]);
			}
			boolean[] cCompSet = compAct[cComp] = new boolean[cGCD];
			for (int cM : cMems) {
				for (int sM = 0; sM < numM[cM]; sM++) {
					if (tVAct[cM][sM]) {
						cCompSet[sM % cGCD] = true;
					}
				}
			}
		}
	}

	void pushConnections() {
		boolean[] cSet = compAct[numC - 1];

		for (int cComp = numC - 2; cComp >= 0; cComp--) {
			boolean[] pSet = cSet;
			cSet = compAct[cComp];
			int gcd = fGCD(pSet.length, cSet.length);

			boolean[] resSet = new boolean[gcd];

			for (int i = 0; i < pSet.length; i++) {
				if (pSet[i]) {
					resSet[i % gcd] = true;
				}
			}

			for (int cRes = 0; cRes < gcd; cRes++) {
				if(resSet[cRes]){
					for (int cNum = cRes; cNum < cSet.length; cNum += gcd) {
						cSet[cNum] = true;
					}
				}
			}
		}
	}

	void findMaxs() {
		max = new int[numTV];

		for (int cComp = 0; cComp < numC; cComp++) {
			int aCnt = 0;
			for (boolean b : compAct[cComp]) {
				if (b) {
					aCnt++;
				}
			}
			for (int cM : sCCs.get(cComp)) {
				max[cM] = numM[cM] / compAct[cComp].length * aCnt;
			}
		}
	}

	// uses Pascal's identity
	void preComb() {
		comb = new int[numTV + 1][];
		comb[0] = new int[] { 1 };
		for (int i = 1; i <= numTV; i++) {
			int[] pRow = comb[i - 1];
			int[] cRow = comb[i] = new int[i + 1];
			cRow[0] = 1;
			for (int j = 1; j < i; j++) {
				int val = pRow[j] + pRow[j - 1];
				cRow[j] = val < 1_000_000_007 ? val : val - 1_000_000_007;
			}
			cRow[i] = 1;
		}
	}

	long findAns() {
		long ans = 0;

		for (int sLws = 0; sLws < numTV; sLws++) {
			int sGrt = 0;
			int pGrt = 0;
			for (int oth = 0; oth < numTV; oth++) {
				if (oth == sLws) {
					continue;
				}
				if (min[oth] > max[sLws]) {
					if (++sGrt >= A) {
						continue;
					}
				}

				// secondary condition in case of equality to prevent overcounting
				else if (max[oth] > max[sLws] || (max[oth] == max[sLws] && sLws < oth)) {
					pGrt++;
				}
			}

			// condition: B - 1 - sGrt <= numT
			int s = B - 1 - sGrt;
			for (int numT = s > 0 ? s : 0; numT < B && numT <= pGrt && numT + sGrt < A; numT++) {
				ans = (ans + ((long) comb[pGrt][numT]) * comb[sGrt][B - 1 - numT]) % MOD;
			}
		}
		return ans;
	}

	@SuppressWarnings("unchecked")
	void execute() throws IOException {
		BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

		StringTokenizer inputData = new StringTokenizer(reader.readLine());
		numTV = Integer.parseInt(inputData.nextToken());
		A = Integer.parseInt(inputData.nextToken());
		B = Integer.parseInt(inputData.nextToken());

		tAList = new ArrayList[numTV];

		for (int i = 0; i < numTV; i++) {
			tAList[i] = new ArrayList<Integer>();
			String nLine = reader.readLine();
			for (int j = 0; j < numTV; j++) {
				if (nLine.charAt(j) == '1') {
					tAList[i].add(j);
				}
			}
		}

		tVAct = new boolean[numTV][];
		numM = new int[numTV];
		min = new int[numTV];

		for (int i = 0; i < numTV; i++) {
			inputData = new StringTokenizer(reader.readLine());
			int cNumM = numM[i] = Integer.parseInt(inputData.nextToken());
			boolean[] cVAct = tVAct[i] = new boolean[cNumM];

			String nLine = inputData.nextToken();
			for (int j = 0; j < cNumM; j++) {
				if (cVAct[j] = nLine.charAt(j) == '1') {
					min[i]++;
				}
			}
		}
		reader.close();

		findSCCs();
		condenseComps();
		pushConnections();
		findMaxs();
		preComb();

		long ans = findAns();
		System.out.println(ans);
	}

	public static void main(String[] args) throws IOException {
		new Div1_411F().execute();
	}

}

import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.BufferedWriter;
import java.util.InputMismatchException;
import java.io.IOException;
import java.util.Stack;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
import java.util.Vector;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.util.BitSet;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        OutputWriter out = new OutputWriter(outputStream);
        TaskF solver = new TaskF();
        solver.solve(1, in, out);
        out.close();
    }

    static class TaskF {
        public int mod = 1000000007;
        public int n;
        public int a;
        public int b;
        public char[][] adj;
        public List<Integer>[] graph;

        public void solve(int testNumber, InputReader in, OutputWriter out) {
            n = in.nextInt();
            a = in.nextInt();
            b = in.nextInt();
            adj = new char[n][n];
            graph = Stream.generate(ArrayList::new).limit(n).toArray(List[]::new);
            for (int i = 0; i < n; i++) adj[i] = in.next().toCharArray();
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < n; j++) {
                    if (adj[i][j] == '1') {
                        graph[i].add(j);
                    }
                }
            }
            List<List<Integer>> comp = new SCCTarjan().scc(graph);
            boolean[][] can = new boolean[n][];
            int[] low = new int[n];
            for (int i = 0; i < n; i++) {
                int q = in.nextInt();
                char[] w = in.next().toCharArray();
                can[i] = new boolean[q];
                for (int j = 0; j < q; j++) {
                    can[i][j] = w[j] == '1';
                    if (can[i][j]) low[i]++;
                }
            }
            int[] wcomp = new int[n];
            int idx = 0;
            List<BitSet> bb = new ArrayList<>();
            List<Integer> bs = new ArrayList<>();
            for (List<Integer> gg : comp) {
                int gcd = 0;
                for (int x : gg) {
                    gcd = Utils.gcd(gcd, can[x].length);
                    wcomp[x] = idx;
                }
                idx++;
                BitSet d = new BitSet(gcd);
                bs.add(gcd);
                bb.add(d);
                for (int x : gg) {
                    for (int i = 0; i < can[x].length; i++) {
                        if (can[x][i]) {
                            d.set(i % gcd, true);
                        }
                    }
                }
            }

            for (List<Integer> gg : comp) {
                for (int x : gg) {
                    for (int y : graph[x]) {
                        if (wcomp[y] != wcomp[x]) {
                            int g = Utils.gcd(bs.get(wcomp[x]), bs.get(wcomp[y]));
                            BitSet ww = new BitSet(g);
                            for (int i = 0; i < bs.get(wcomp[x]); i++) {
                                if (bb.get(wcomp[x]).get(i))
                                    ww.set(i % g, true);
                            }
                            for (int i = 0; i < bs.get(wcomp[y]); i++) {
                                if (ww.get(i % g)) {
                                    bb.get(wcomp[y]).set(i, true);
                                }
                            }
                        }
                    }
                }
            }
            int[] high = new int[n];
            for (int i = 0; i < n; i++) {
                high[i] = can[i].length;
//            for (int j = 0; j < can[i].length; j++) {
//                if (bb.get(wcomp[i]).get(j%bs.get(wcomp[i])))
//                    high[i]++;
//            }
            }
            long ret = 0;
            int[][] comb = Utils.getComb(n + 1, mod);
            for (int lowest = 0; lowest < n; lowest++) {
                int countabove = 0;
                for (int other = 0; other < n; other++) {
                    if (other == lowest) continue;
                    if (low[other] > high[lowest]) {
                        countabove++;
                    }
                }
                if (countabove >= a) {
                    continue;
                }
                int canbig = 0;
                for (int other = 0; other < n; other++) {
                    if (other == lowest) continue;
                    if (low[other] <= high[lowest] && (high[other] > high[lowest] || (high[other] == high[lowest] && other > lowest))) {
                        canbig++;
                    }
                }

                for (int take = 0; take < b && take <= canbig; take++) {
                    ret = (ret + 1L * comb[canbig][take] * comb[countabove][b - take - 1]) % mod;
                }
            }
            out.println(ret);
        }

    }

    static class OutputWriter {
        private final PrintWriter writer;

        public OutputWriter(OutputStream outputStream) {
            writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream)));
        }

        public OutputWriter(Writer writer) {
            this.writer = new PrintWriter(writer);
        }

        public void close() {
            writer.close();
        }

        public void println(long i) {
            writer.println(i);
        }

    }

    static class Utils {
        public static int gcd(int a, int b) {
            return b == 0 ? a : gcd(b, a % b);
        }

        public static int[][] getComb(int sz, int mod) {
            int[][] comb = new int[sz][sz];
            for (int i = 0; i < sz; i++) {
                comb[i][0] = 1;
                for (int j = 1; j <= i; j++) {
                    comb[i][j] = comb[i - 1][j] + comb[i - 1][j - 1];
                    if (comb[i][j] >= mod) comb[i][j] -= mod;
                }
            }
            return comb;
        }

    }

    static class InputReader {
        private InputStream stream;
        private byte[] buf = new byte[1024];
        private int curChar;
        private int numChars;

        public InputReader(InputStream stream) {
            this.stream = stream;
        }

        public int read() {
            if (this.numChars == -1) {
                throw new InputMismatchException();
            } else {
                if (this.curChar >= this.numChars) {
                    this.curChar = 0;

                    try {
                        this.numChars = this.stream.read(this.buf);
                    } catch (IOException var2) {
                        throw new InputMismatchException();
                    }

                    if (this.numChars <= 0) {
                        return -1;
                    }
                }

                return this.buf[this.curChar++];
            }
        }

        public int nextInt() {
            int c;
            for (c = this.read(); isSpaceChar(c); c = this.read()) {
                ;
            }

            byte sgn = 1;
            if (c == 45) {
                sgn = -1;
                c = this.read();
            }

            int res = 0;

            while (c >= 48 && c <= 57) {
                res *= 10;
                res += c - 48;
                c = this.read();
                if (isSpaceChar(c)) {
                    return res * sgn;
                }
            }

            throw new InputMismatchException();
        }

        public String next() {
            int c;
            while (isSpaceChar(c = this.read())) {
                ;
            }

            StringBuilder result = new StringBuilder();
            result.appendCodePoint(c);

            while (!isSpaceChar(c = this.read())) {
                result.appendCodePoint(c);
            }

            return result.toString();
        }

        public static boolean isSpaceChar(int c) {
            return c == 32 || c == 10 || c == 13 || c == 9 || c == -1;
        }

    }

    static class SCCTarjan {
        List<Integer>[] graph;
        boolean[] visited;
        Stack<Integer> stack;
        int time;
        int[] lowlink;
        List<List<Integer>> components;

        public List<List<Integer>> scc(List<Integer>[] graph) {
            int n = graph.length;
            this.graph = graph;
            visited = new boolean[n];
            stack = new Stack<>();
            time = 0;
            lowlink = new int[n];
            components = new ArrayList<>();

            for (int u = 0; u < n; u++)
                if (!visited[u])
                    dfs(u);

            return components;
        }

        void dfs(int u) {
            lowlink[u] = time++;
            visited[u] = true;
            stack.add(u);
            boolean isComponentRoot = true;

            for (int v : graph[u]) {
                if (!visited[v])
                    dfs(v);
                if (lowlink[u] > lowlink[v]) {
                    lowlink[u] = lowlink[v];
                    isComponentRoot = false;
                }
            }

            if (isComponentRoot) {
                List<Integer> component = new ArrayList<>();
                while (true) {
                    int x = stack.pop();
                    component.add(x);
                    lowlink[x] = Integer.MAX_VALUE;
                    if (x == u)
                        break;
                }
                components.add(component);
            }
        }

    }
}

import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.BufferedWriter;
import java.util.InputMismatchException;
import java.io.IOException;
import java.util.Stack;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
import java.util.Vector;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.util.BitSet;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        OutputWriter out = new OutputWriter(outputStream);
        TaskF solver = new TaskF();
        solver.solve(1, in, out);
        out.close();
    }

    static class TaskF {
        public int mod = 1000000007;
        public int n;
        public int a;
        public int b;
        public char[][] adj;
        public List<Integer>[] graph;

        public void solve(int testNumber, InputReader in, OutputWriter out) {
            n = in.nextInt();
            a = in.nextInt();
            b = in.nextInt();
            adj = new char[n][n];
            graph = Stream.generate(ArrayList::new).limit(n).toArray(List[]::new);
            for (int i = 0; i < n; i++) adj[i] = in.next().toCharArray();
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < n; j++) {
                    if (adj[i][j] == '1') {
                        graph[i].add(j);
                    }
                }
            }
            List<List<Integer>> comp = new SCCTarjan().scc(graph);
            boolean[][] can = new boolean[n][];
            int[] low = new int[n];
            for (int i = 0; i < n; i++) {
                int q = in.nextInt();
                char[] w = in.next().toCharArray();
                can[i] = new boolean[q];
                for (int j = 0; j < q; j++) {
                    can[i][j] = w[j] == '1';
                    if (can[i][j]) low[i]++;
                }
            }
            int[] wcomp = new int[n];
            int idx = 0;
            List<BitSet> bb = new ArrayList<>();
            List<Integer> bs = new ArrayList<>();
            for (List<Integer> gg : comp) {
                int gcd = 0;
                for (int x : gg) {
                    gcd = Utils.gcd(gcd, can[x].length);
                    wcomp[x] = idx;
                }
                idx++;
                BitSet d = new BitSet(gcd);
                bs.add(gcd);
                bb.add(d);
                for (int x : gg) {
                    for (int i = 0; i < can[x].length; i++) {
                        if (can[x][i]) {
                            d.set(i % gcd, true);
                        }
                    }
                }
            }

            for (List<Integer> gg : comp) {
                for (int x : gg) {
                    for (int y : graph[x]) {
                        if (wcomp[y] != wcomp[x]) {
                            int g = Utils.gcd(bs.get(wcomp[x]), bs.get(wcomp[y]));
                            BitSet ww = new BitSet(g);
                            for (int i = 0; i < bs.get(wcomp[x]); i += g) {
                                ww.or(bb.get(wcomp[x]).get(i, i + g));
                            }
                            for (int i = 0; i < bs.get(wcomp[y]); i++) {
                                if (ww.get(i % g)) {
                                    bb.get(wcomp[y]).set(i, true);
                                }
                            }
                        }
                    }
                }
            }
            int[] high = new int[n];
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < can[i].length; j++) {
                    if (bb.get(wcomp[i]).get(j % bs.get(wcomp[i])))
                        high[i]++;
                }
            }
            long ret = 0;
            int[][] comb = Utils.getComb(n + 1, mod);
            for (int lowest = 0; lowest < n; lowest++) {
                int countabove = 0;
                for (int other = 0; other < n; other++) {
                    if (other == lowest) continue;
                    if (low[other] > high[lowest]) {
                        countabove++;
                    }
                }
                if (countabove >= a) {
                    continue;
                }
                int canbig = 0;
                for (int other = 0; other < n; other++) {
                    if (other == lowest) continue;
                    if (low[other] <= high[lowest] && (high[other] > high[lowest] || (high[other] == high[lowest] && other > lowest))) {
                        canbig++;
                    }
                }

                for (int take = 0; take < b && take <= canbig; take++) {
                    ret = (ret + 1L * comb[canbig][take] * comb[countabove][b - take - 1]) % mod;
                }
            }
            out.println(ret);
        }

    }

    static class OutputWriter {
        private final PrintWriter writer;

        public OutputWriter(OutputStream outputStream) {
            writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream)));
        }

        public OutputWriter(Writer writer) {
            this.writer = new PrintWriter(writer);
        }

        public void close() {
            writer.close();
        }

        public void println(long i) {
            writer.println(i);
        }

    }

    static class Utils {
        public static int gcd(int a, int b) {
            return b == 0 ? a : gcd(b, a % b);
        }

        public static int[][] getComb(int sz, int mod) {
            int[][] comb = new int[sz][sz];
            for (int i = 0; i < sz; i++) {
                comb[i][0] = 1;
                for (int j = 1; j <= i; j++) {
                    comb[i][j] = comb[i - 1][j] + comb[i - 1][j - 1];
                    if (comb[i][j] >= mod) comb[i][j] -= mod;
                }
            }
            return comb;
        }

    }

    static class InputReader {
        private InputStream stream;
        private byte[] buf = new byte[1024];
        private int curChar;
        private int numChars;

        public InputReader(InputStream stream) {
            this.stream = stream;
        }

        public int read() {
            if (this.numChars == -1) {
                throw new InputMismatchException();
            } else {
                if (this.curChar >= this.numChars) {
                    this.curChar = 0;

                    try {
                        this.numChars = this.stream.read(this.buf);
                    } catch (IOException var2) {
                        throw new InputMismatchException();
                    }

                    if (this.numChars <= 0) {
                        return -1;
                    }
                }

                return this.buf[this.curChar++];
            }
        }

        public int nextInt() {
            int c;
            for (c = this.read(); isSpaceChar(c); c = this.read()) {
                ;
            }

            byte sgn = 1;
            if (c == 45) {
                sgn = -1;
                c = this.read();
            }

            int res = 0;

            while (c >= 48 && c <= 57) {
                res *= 10;
                res += c - 48;
                c = this.read();
                if (isSpaceChar(c)) {
                    return res * sgn;
                }
            }

            throw new InputMismatchException();
        }

        public String next() {
            int c;
            while (isSpaceChar(c = this.read())) {
                ;
            }

            StringBuilder result = new StringBuilder();
            result.appendCodePoint(c);

            while (!isSpaceChar(c = this.read())) {
                result.appendCodePoint(c);
            }

            return result.toString();
        }

        public static boolean isSpaceChar(int c) {
            return c == 32 || c == 10 || c == 13 || c == 9 || c == -1;
        }

    }

    static class SCCTarjan {
        List<Integer>[] graph;
        boolean[] visited;
        Stack<Integer> stack;
        int time;
        int[] lowlink;
        List<List<Integer>> components;

        public List<List<Integer>> scc(List<Integer>[] graph) {
            int n = graph.length;
            this.graph = graph;
            visited = new boolean[n];
            stack = new Stack<>();
            time = 0;
            lowlink = new int[n];
            components = new ArrayList<>();

            for (int u = 0; u < n; u++)
                if (!visited[u])
                    dfs(u);

            return components;
        }

        void dfs(int u) {
            lowlink[u] = time++;
            visited[u] = true;
            stack.add(u);
            boolean isComponentRoot = true;

            for (int v : graph[u]) {
                if (!visited[v])
                    dfs(v);
                if (lowlink[u] > lowlink[v]) {
                    lowlink[u] = lowlink[v];
                    isComponentRoot = false;
                }
            }

            if (isComponentRoot) {
                List<Integer> component = new ArrayList<>();
                while (true) {
                    int x = stack.pop();
                    component.add(x);
                    lowlink[x] = Integer.MAX_VALUE;
                    if (x == u)
                        break;
                }
                components.add(component);
            }
        }

    }
}

import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.BufferedWriter;
import java.util.InputMismatchException;
import java.io.IOException;
import java.util.Stack;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
import java.util.Vector;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.util.BitSet;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        OutputWriter out = new OutputWriter(outputStream);
        TaskF solver = new TaskF();
        solver.solve(1, in, out);
        out.close();
    }

    static class TaskF {
        public int mod = 1000000007;
        public int n;
        public int a;
        public int b;
        public char[][] adj;
        public List<Integer>[] graph;

        public void solve(int testNumber, InputReader in, OutputWriter out) {
            n = in.nextInt();
            a = in.nextInt();
            b = in.nextInt();
            adj = new char[n][n];
            graph = Stream.generate(ArrayList::new).limit(n).toArray(List[]::new);
            for (int i = 0; i < n; i++) adj[i] = in.next().toCharArray();
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < n; j++) {
                    if (adj[i][j] == '1') {
                        graph[i].add(j);
                    }
                }
            }
            List<List<Integer>> comp = new SCCTarjan().scc(graph);
            boolean[][] can = new boolean[n][];
            int[] low = new int[n];
            for (int i = 0; i < n; i++) {
                int q = in.nextInt();
                char[] w = in.next().toCharArray();
                can[i] = new boolean[q];
                for (int j = 0; j < q; j++) {
                    can[i][j] = w[j] == '1';
                    if (can[i][j]) low[i]++;
                }
            }
            int[] wcomp = new int[n];
            int idx = 0;
            List<BitSet> bb = new ArrayList<>();
            List<Integer> bs = new ArrayList<>();
            for (List<Integer> gg : comp) {
                int gcd = 0;
                for (int x : gg) {
                    gcd = Utils.gcd(gcd, can[x].length);
                    wcomp[x] = idx;
                }
                idx++;
                BitSet d = new BitSet(gcd);
                bs.add(gcd);
                bb.add(d);
                for (int x : gg) {
                    for (int i = 0; i < can[x].length; i++) {
                        if (can[x][i]) {
                            d.set(i % gcd, true);
                        }
                    }
                }
            }

            for (List<Integer> gg : comp) {
                for (int x : gg) {
                    for (int y : graph[x]) {
                        if (wcomp[y] != wcomp[x]) {
                            int g = Utils.gcd(bs.get(wcomp[x]), bs.get(wcomp[y]));
                            BitSet ww = new BitSet(g);
                            for (int i = 0; i < bs.get(wcomp[x]); i++) {
                                if (bb.get(wcomp[x]).get(i))
                                    ww.set(i % g, true);
                            }
                            for (int i = 0; i < bs.get(wcomp[y]); i++) {
                                if (ww.get(i % g)) {
                                    bb.get(wcomp[y]).set(i, true);
                                }
                            }
                        }
                    }
                }
            }
            int[] high = new int[n];
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < can[i].length; j++) {
                    if (bb.get(wcomp[i]).get(j % bs.get(wcomp[i])))
                        high[i]++;
                }
            }
            long ret = 0;
            int[][] comb = Utils.getComb(n + 1, mod);
            for (int lowest = 0; lowest < n; lowest++) {
                int countabove = 0;
                for (int other = 0; other < n; other++) {
                    if (other == lowest) continue;
                    if (low[other] > high[lowest]) {
                        countabove++;
                    }
                }
                if (countabove >= a) {
                    continue;
                }
                int canbig = 0;
                for (int other = 0; other < n; other++) {
                    if (other == lowest) continue;
                    if (low[other] <= high[lowest] && (high[other] > high[lowest] || (high[other] == high[lowest] && other > lowest))) {
                        canbig++;
                    }
                }

                for (int take = 0; take < b && take <= canbig; take++) {
                    ret = (ret + 1L * comb[canbig][take] * comb[countabove][b - take - 1]) % mod;
                }
            }
            out.println(ret);
        }

    }

    static class OutputWriter {
        private final PrintWriter writer;

        public OutputWriter(OutputStream outputStream) {
            writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream)));
        }

        public OutputWriter(Writer writer) {
            this.writer = new PrintWriter(writer);
        }

        public void close() {
            writer.close();
        }

        public void println(long i) {
            writer.println(i);
        }

    }

    static class Utils {
        public static int gcd(int a, int b) {
            return b == 0 ? a : gcd(b, a % b);
        }

        public static int[][] getComb(int sz, int mod) {
            int[][] comb = new int[sz][sz];
            for (int i = 0; i < sz; i++) {
                comb[i][0] = 1;
                for (int j = 1; j <= i; j++) {
                    comb[i][j] = comb[i - 1][j] + comb[i - 1][j - 1];
                    if (comb[i][j] >= mod) comb[i][j] -= mod;
                }
            }
            return comb;
        }

    }

    static class InputReader {
        private InputStream stream;
        private byte[] buf = new byte[1024];
        private int curChar;
        private int numChars;

        public InputReader(InputStream stream) {
            this.stream = stream;
        }

        public int read() {
            if (this.numChars == -1) {
                throw new InputMismatchException();
            } else {
                if (this.curChar >= this.numChars) {
                    this.curChar = 0;

                    try {
                        this.numChars = this.stream.read(this.buf);
                    } catch (IOException var2) {
                        throw new InputMismatchException();
                    }

                    if (this.numChars <= 0) {
                        return -1;
                    }
                }

                return this.buf[this.curChar++];
            }
        }

        public int nextInt() {
            int c;
            for (c = this.read(); isSpaceChar(c); c = this.read()) {
                ;
            }

            byte sgn = 1;
            if (c == 45) {
                sgn = -1;
                c = this.read();
            }

            int res = 0;

            while (c >= 48 && c <= 57) {
                res *= 10;
                res += c - 48;
                c = this.read();
                if (isSpaceChar(c)) {
                    return res * sgn;
                }
            }

            throw new InputMismatchException();
        }

        public String next() {
            int c;
            while (isSpaceChar(c = this.read())) {
                ;
            }

            StringBuilder result = new StringBuilder();
            result.appendCodePoint(c);

            while (!isSpaceChar(c = this.read())) {
                result.appendCodePoint(c);
            }

            return result.toString();
        }

        public static boolean isSpaceChar(int c) {
            return c == 32 || c == 10 || c == 13 || c == 9 || c == -1;
        }

    }

    static class SCCTarjan {
        List<Integer>[] graph;
        boolean[] visited;
        Stack<Integer> stack;
        int time;
        int[] lowlink;
        List<List<Integer>> components;

        public List<List<Integer>> scc(List<Integer>[] graph) {
            int n = graph.length;
            this.graph = graph;
            visited = new boolean[n];
            stack = new Stack<>();
            time = 0;
            lowlink = new int[n];
            components = new ArrayList<>();

            for (int u = 0; u < n; u++)
                if (!visited[u])
                    dfs(u);

            return components;
        }

        void dfs(int u) {
            lowlink[u] = time++;
            visited[u] = true;
            stack.add(u);
            boolean isComponentRoot = true;

            for (int v : graph[u]) {
                if (!visited[v])
                    dfs(v);
                if (lowlink[u] > lowlink[v]) {
                    lowlink[u] = lowlink[v];
                    isComponentRoot = false;
                }
            }

            if (isComponentRoot) {
                List<Integer> component = new ArrayList<>();
                while (true) {
                    int x = stack.pop();
                    component.add(x);
                    lowlink[x] = Integer.MAX_VALUE;
                    if (x == u)
                        break;
                }
                components.add(component);
            }
        }

    }
}

import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.BufferedWriter;
import java.util.InputMismatchException;
import java.io.IOException;
import java.util.Stack;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
import java.util.Vector;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.util.BitSet;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        OutputWriter out = new OutputWriter(outputStream);
        TaskF solver = new TaskF();
        solver.solve(1, in, out);
        out.close();
    }

    static class TaskF {
        public int mod = 1000000007;
        public int n;
        public int a;
        public int b;
        public char[][] adj;
        public List<Integer>[] graph;

        public void solve(int testNumber, InputReader in, OutputWriter out) {
            n = in.nextInt();
            a = in.nextInt();
            b = in.nextInt();
            adj = new char[n][n];
            graph = Stream.generate(ArrayList::new).limit(n).toArray(List[]::new);
            for (int i = 0; i < n; i++) adj[i] = in.next().toCharArray();
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < n; j++) {
                    if (adj[i][j] == '1') {
                        graph[i].add(j);
                    }
                }
            }
            List<List<Integer>> comp = new SCCTarjan().scc(graph);
            boolean[][] can = new boolean[n][];
            int[] low = new int[n];
            for (int i = 0; i < n; i++) {
                int q = in.nextInt();
                char[] w = in.next().toCharArray();
                can[i] = new boolean[q];
                for (int j = 0; j < q; j++) {
                    can[i][j] = w[j] == '1';
                    if (can[i][j]) low[i]++;
                }
            }
            int[] wcomp = new int[n];
            int idx = 0;
            List<BitSet> bb = new ArrayList<>();
            List<Integer> bs = new ArrayList<>();
            for (List<Integer> gg : comp) {
                int gcd = 0;
                for (int x : gg) {
                    gcd = Utils.gcd(gcd, can[x].length);
                    wcomp[x] = idx;
                }
                idx++;
                BitSet d = new BitSet(gcd);
                bs.add(gcd);
                bb.add(d);
                for (int x : gg) {
                    for (int i = 0; i < can[x].length; i++) {
                        if (can[x][i]) {
                            d.set(i % gcd, true);
                        }
                    }
                }
            }

            for (List<Integer> gg : comp) {
                for (int x : gg) {
                    for (int y : graph[x]) {
                        if (wcomp[y] != wcomp[x]) {
                            int g = Utils.gcd(bs.get(wcomp[x]), bs.get(wcomp[y]));
                            BitSet ww = new BitSet(g);
                            for (int i = 0; i < bs.get(wcomp[x]); i += g) {
                                ww.or(bb.get(wcomp[x]).get(i, i + g));
                            }
                            for (int i = 0; i < bs.get(wcomp[y]); i++) {
                                if (ww.get(i % g)) {
                                    bb.get(wcomp[y]).set(i, true);
                                }
                            }
                        }
                    }
                }
            }
            int[] high = new int[n];
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < can[i].length; j++) {
                    if (bb.get(wcomp[i]).get(j % bs.get(wcomp[i])))
                        high[i]++;
                }
            }
            long ret = 0;
            int[][] comb = Utils.getComb(n + 1, mod);
            for (int lowest = 0; lowest < n; lowest++) {
                int countabove = 0;
                for (int other = 0; other < n; other++) {
                    if (other == lowest) continue;
                    if (low[other] > high[lowest]) {
                        countabove++;
                    }
                }
                if (countabove >= a) {
                    continue;
                }
                int canbig = 0;
                for (int other = 0; other < n; other++) {
                    if (other == lowest) continue;
                    if (low[other] <= high[lowest] && high[other] >= high[lowest]) {
                        canbig++;
                    }
                }

                for (int take = 0; take < b && take <= canbig; take++) {
                    ret = (ret + 1L * comb[canbig][take] * comb[countabove][b - take - 1]) % mod;
                }
            }
            out.println(ret);
        }

    }

    static class OutputWriter {
        private final PrintWriter writer;

        public OutputWriter(OutputStream outputStream) {
            writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream)));
        }

        public OutputWriter(Writer writer) {
            this.writer = new PrintWriter(writer);
        }

        public void close() {
            writer.close();
        }

        public void println(long i) {
            writer.println(i);
        }

    }

    static class Utils {
        public static int gcd(int a, int b) {
            return b == 0 ? a : gcd(b, a % b);
        }

        public static int[][] getComb(int sz, int mod) {
            int[][] comb = new int[sz][sz];
            for (int i = 0; i < sz; i++) {
                comb[i][0] = 1;
                for (int j = 1; j <= i; j++) {
                    comb[i][j] = comb[i - 1][j] + comb[i - 1][j - 1];
                    if (comb[i][j] >= mod) comb[i][j] -= mod;
                }
            }
            return comb;
        }

    }

    static class InputReader {
        private InputStream stream;
        private byte[] buf = new byte[1024];
        private int curChar;
        private int numChars;

        public InputReader(InputStream stream) {
            this.stream = stream;
        }

        public int read() {
            if (this.numChars == -1) {
                throw new InputMismatchException();
            } else {
                if (this.curChar >= this.numChars) {
                    this.curChar = 0;

                    try {
                        this.numChars = this.stream.read(this.buf);
                    } catch (IOException var2) {
                        throw new InputMismatchException();
                    }

                    if (this.numChars <= 0) {
                        return -1;
                    }
                }

                return this.buf[this.curChar++];
            }
        }

        public int nextInt() {
            int c;
            for (c = this.read(); isSpaceChar(c); c = this.read()) {
                ;
            }

            byte sgn = 1;
            if (c == 45) {
                sgn = -1;
                c = this.read();
            }

            int res = 0;

            while (c >= 48 && c <= 57) {
                res *= 10;
                res += c - 48;
                c = this.read();
                if (isSpaceChar(c)) {
                    return res * sgn;
                }
            }

            throw new InputMismatchException();
        }

        public String next() {
            int c;
            while (isSpaceChar(c = this.read())) {
                ;
            }

            StringBuilder result = new StringBuilder();
            result.appendCodePoint(c);

            while (!isSpaceChar(c = this.read())) {
                result.appendCodePoint(c);
            }

            return result.toString();
        }

        public static boolean isSpaceChar(int c) {
            return c == 32 || c == 10 || c == 13 || c == 9 || c == -1;
        }

    }

    static class SCCTarjan {
        List<Integer>[] graph;
        boolean[] visited;
        Stack<Integer> stack;
        int time;
        int[] lowlink;
        List<List<Integer>> components;

        public List<List<Integer>> scc(List<Integer>[] graph) {
            int n = graph.length;
            this.graph = graph;
            visited = new boolean[n];
            stack = new Stack<>();
            time = 0;
            lowlink = new int[n];
            components = new ArrayList<>();

            for (int u = 0; u < n; u++)
                if (!visited[u])
                    dfs(u);

            return components;
        }

        void dfs(int u) {
            lowlink[u] = time++;
            visited[u] = true;
            stack.add(u);
            boolean isComponentRoot = true;

            for (int v : graph[u]) {
                if (!visited[v])
                    dfs(v);
                if (lowlink[u] > lowlink[v]) {
                    lowlink[u] = lowlink[v];
                    isComponentRoot = false;
                }
            }

            if (isComponentRoot) {
                List<Integer> component = new ArrayList<>();
                while (true) {
                    int x = stack.pop();
                    component.add(x);
                    lowlink[x] = Integer.MAX_VALUE;
                    if (x == u)
                        break;
                }
                components.add(component);
            }
        }

    }
}

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.StringTokenizer;

public class Div1_411F {

	int numTV;
	int A;
	int B;

	ArrayList<Integer>[] tAList;

	boolean[][] tVAct;
	int[] numM;

	int cTime = 0;
	int[] disc;
	int[] low;

	ArrayDeque<Integer> stack = new ArrayDeque<Integer>();

	ArrayList<ArrayList<Integer>> sCCs = new ArrayList<ArrayList<Integer>>();

	int numC;

	boolean[] visited;

	boolean[][] compAct;

	// represents the minimum and the maximum amounts of active members a tournament vertex can have
	int[] min;
	int[] max;

	long MOD = 1_000_000_007;

	int[][] comb;

	void dfs(int cV) {
		disc[cV] = low[cV] = cTime++;
		stack.push(cV);

		for (int adj : tAList[cV]) {
			if (disc[adj] == -1) {
				dfs(adj);
			}
			if (low[adj] < low[cV]) {
				low[cV] = low[adj];
			}
		}
		if (disc[cV] == low[cV]) {
			ArrayList<Integer> cSCC = new ArrayList<Integer>();
			while (stack.peek() != cV) {
				low[stack.peek()] = Integer.MAX_VALUE;
				cSCC.add(stack.pop());
			}
			low[stack.pop()] = Integer.MAX_VALUE;
			cSCC.add(cV);
			sCCs.add(cSCC);
		}
	}

	void findSCCs() {
		disc = new int[numTV];
		low = new int[numTV];
		Arrays.fill(disc, -1);

		for (int i = 0; i < numTV; i++) {
			if (disc[i] == -1) {
				dfs(i);
			}
		}

		numC = sCCs.size();
	}

	int fGCD(int a, int b) {
		while (b != 0) {
			int t = b;
			b = a % b;
			a = t;
		}
		return a;
	}

	void condenseComps() {
		compAct = new boolean[numC][];
		for (int cComp = 0; cComp < numC; cComp++) {
			ArrayList<Integer> cMems = sCCs.get(cComp);
			int cGCD = numM[cMems.get(0)];
			for (int j : cMems) {
				cGCD = fGCD(cGCD, numM[j]);
			}
			boolean[] cCompSet = compAct[cComp] = new boolean[cGCD];
			for (int cM : cMems) {
				for (int sM = 0; sM < numM[cM]; sM++) {
					if (tVAct[cM][sM]) {
						cCompSet[sM % cGCD] = true;
					}
				}
			}
		}
	}

	void pushConnections() {
		boolean[] cSet = compAct[numC - 1];

		for (int cComp = numC - 1; cComp >= 0; cComp--) {
			boolean[] pSet = cSet;
			cSet = compAct[cComp];
			int gcd = fGCD(pSet.length, cSet.length);

			boolean[] resSet = new boolean[gcd];

			for (int i = 0; i < pSet.length; i++) {
				if (pSet[i]) {
					resSet[i % gcd] = true;
				}
			}

			for (int cRes = 0; cRes < gcd; cRes++) {
				for (int cNum = cRes; cNum < cSet.length; cNum += gcd) {
					cSet[cNum] = true;
				}
			}
		}
	}

	void findMaxs() {
		max = new int[numTV];

		for (int cComp = 0; cComp < numC; cComp++) {
			int aCnt = 0;
			for (boolean b : compAct[cComp]) {
				if (b) {
					aCnt++;
				}
			}
			for (int cM : sCCs.get(cComp)) {
				max[cM] = numM[cM] / compAct[cComp].length * aCnt;
			}
		}
	}

	// uses Pascal's identity
	void preComb() {
		comb = new int[numTV + 1][];
		comb[0] = new int[] { 1 };
		for (int i = 1; i <= numTV; i++) {
			int[] pRow = comb[i - 1];
			int[] cRow = comb[i] = new int[i + 1];
			cRow[0] = 1;
			for (int j = 1; j < i; j++) {
				int val = pRow[j] + pRow[j - 1];
				cRow[j] = val < 1_000_000_007 ? val : val - 1_000_000_007;
			}
			cRow[i] = 1;
		}
	}

	long findAns() {
		long ans = 0;

		for (int sLws = 0; sLws < numTV; sLws++) {
			int sGrt = 0;
			int pGrt = 0;
			for (int oth = 0; oth < numTV; oth++) {
				if (oth == sLws) {
					continue;
				}
				if (min[oth] > max[sLws]) {
					if (++sGrt >= A) {
						continue;
					}
				}

				// secondary condition in case of equality to prevent overcounting
				else if (max[oth] > max[sLws] || (max[oth] == max[sLws] && sLws < oth)) {
					pGrt++;
				}
			}

			// condition: B - 1 - sGrt <= numT
			int s = B - 1 - sGrt;
			for (int numT = s > 0 ? s : 0; numT < B && numT <= pGrt && numT + sGrt < A; numT++) {
				ans = (ans + ((long) comb[pGrt][numT]) * comb[sGrt][B - 1 - numT]) % MOD;
			}
		}
		return ans;
	}

	@SuppressWarnings("unchecked")
	void execute() throws IOException {
		BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

		StringTokenizer inputData = new StringTokenizer(reader.readLine());
		numTV = Integer.parseInt(inputData.nextToken());
		A = Integer.parseInt(inputData.nextToken());
		B = Integer.parseInt(inputData.nextToken());

		tAList = new ArrayList[numTV];

		for (int i = 0; i < numTV; i++) {
			tAList[i] = new ArrayList<Integer>();
			String nLine = reader.readLine();
			for (int j = 0; j < numTV; j++) {
				if (nLine.charAt(j) == '1') {
					tAList[i].add(j);
				}
			}
		}

		tVAct = new boolean[numTV][];
		numM = new int[numTV];
		min = new int[numTV];

		for (int i = 0; i < numTV; i++) {
			inputData = new StringTokenizer(reader.readLine());
			int cNumM = numM[i] = Integer.parseInt(inputData.nextToken());
			boolean[] cVAct = tVAct[i] = new boolean[cNumM];

			String nLine = inputData.nextToken();
			for (int j = 0; j < cNumM; j++) {
				if (cVAct[j] = nLine.charAt(j) == '1') {
					min[i]++;
				}
			}
		}
		reader.close();

		findSCCs();
		condenseComps();
		pushConnections();
		findMaxs();
		preComb();

		long ans = findAns();
		System.out.println(ans);
	}

	public static void main(String[] args) throws IOException {
		new Div1_411F().execute();
	}

}