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.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.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();
	}

}