import java.util.List;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.io.BufferedReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.StringTokenizer;
import java.util.Collections;
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;
		FastScanner in = new FastScanner(inputStream);
		PrintWriter out = new PrintWriter(outputStream);
		TaskE solver = new TaskE();
		solver.solve(1, in, out);
		out.close();
	}
}

class TaskE {
        final int MAX_N = 101_000;
        @SuppressWarnings("uncheked")
        ArrayList<Integer>[] divs = new ArrayList[MAX_N];
        long modulo;

        public void solve(int testNumber, FastScanner in, PrintWriter out) {
                init();
                int n = in.nextInt();
                int m = in.nextInt();
                long L = in.nextInt();
                long R = in.nextInt();
                modulo = in.nextInt();
                long res = 0;
                for (long dx = 1; dx <= n; dx++) {
                        long low = L * L - dx * dx;
                        long high = R * R - dx * dx;
                        if (low < 0)
                                low = 0;
                        if (high < 0)
                                continue;
                        long left = (int)Math.sqrt(low);
                        long right = (int)Math.sqrt(high);
                        while (left > 0 && left * left + dx * dx > L * L)
                                left--;
                        while (left * left + dx * dx <= L * L)
                                left++;
                        left--;
                        while (right > 0 && right * right + dx * dx > R * R)
                                left--;
                        while (right * right + dx * dx <= R * R)
                                right++;
                        right--;
                        if (right <= 0)
                                continue;
                        if (left < 0)
                                left = 0;
                        if (right > m)
                                right = m;
                        if (left > right)
                                continue;
                        long cntR = right - getCount((int)dx, (int)right);
                        long cntL = left - getCount((int)dx, (int)left);
                        long cnt = cntR - cntL;
                        cnt %= modulo;
                        cnt += modulo;
                        cnt %= modulo;
                        long sumR = right * (right + 1) / 2 - getSum((int)dx, (int)right);
                        long sumL = left * (left + 1) / 2 - getSum((int)dx, (int)left);
                        long sum = sumR - sumL;
                        sum = cnt * (m + 1) % modulo - sum;
                        sum %= modulo;
                        sum += modulo;
                        sum %= modulo;
                        res += (2 * sum * (n - dx + 1)) % modulo;
                        res %= modulo;
                }
                if (L <= 1)
                        res += (n + 1) * 1L * m + n * 1L * (m + 1);
                out.println(res % modulo);
        }

        void init() {
                for (int i = 1; i < MAX_N; i++) {
                        divs[i] = new ArrayList<>();
                        divs[i].add(1);
                }
                for (int i = 2; i < MAX_N; i++)
                        for (int j = i; j < MAX_N; j += i)
                                divs[j].add(i);
                for (int i = 1; i < MAX_N; i++)
                        Collections.reverse(divs[i]);
        }

        long getCount(int n, int R) {
                if (n == 1)
                        return 0L;
                if (R <= 1)
                        return 0L;
                int cnt = divs[n].size();
                int[] with = new int[cnt];
                long res = 0;
                for (int i = 0; i < cnt - 1; i++) {
                        int cur = divs[n].get(i);
                        with[i] += R / cur;
                        res += with[i];
                        for (int j = cnt - 1; j >= 0 && divs[n].get(j) < cur; j--)
                                if (cur % divs[n].get(j) == 0)
                                        with[j] -= with[i];
                }
                return res;
        }

        long getSum(int n, int R) {
                if (R <= 1)
                        return 0L;
                if (n == 1)
                        return 0L;
                int cnt = divs[n].size();
                long[] with = new long[cnt];
                long res = 0;
                for (int i = 0; i < cnt - 1; i++) {
                        int cur = divs[n].get(i);
                        with[i] += (R / cur * 1L * (R / cur + 1) / 2) % modulo * cur;
                        with[i] %= modulo;
                        res += with[i];
                        res %= modulo;
                        for (int j = cnt - 1; j >= 0 && divs[n].get(j) < cur; j--)
                                if (cur % divs[n].get(j) == 0) {
                                        with[j] -= with[i];
                                        with[j] %= modulo;
                                        if (with[j] < 0)
                                                with[j] += modulo;
                                }
                }
                return res;
        }
}

class FastScanner {
        BufferedReader reader;
        StringTokenizer tokenizer;

        public FastScanner(InputStream inputStream)  {
                reader = new BufferedReader(new InputStreamReader(inputStream));
        }

        public String nextToken() {
                while (tokenizer == null || !tokenizer.hasMoreTokens()) {
                        String line;
                        try {
                                line = reader.readLine();
                        } catch (IOException e) {
                                return null;
                        }
                        tokenizer = new StringTokenizer(line);
                }
                return tokenizer.nextToken();
        }

        public int nextInt() {
                return Integer.parseInt(nextToken());
        }

        }


//package round235;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.InputMismatchException;

public class E2 {
	InputStream is;
	PrintWriter out;
	String INPUT = "";

	void solve()
	{
		int n = ni(), m = ni();
		int L = ni(), R = ni(), p = ni();

		long ret = 0;
		if(L == 1){
			ret += (long)n*(m+1)+(long)(n+1)*m;
			ret %= p;
		}

		Arrays.fill(counts, -1);
		long xsum = countx(n, m, 1, (long)R*R);
		Arrays.fill(counts, -1);
		long xsum2 = countx(n, m, 1, (long)L*L-1);
		Arrays.fill(counts, -1);
		long ysum = countx(m, n, 1, (long)R*R);
		Arrays.fill(counts, -1);
		long ysum2 = countx(m, n, 1, (long)L*L-1);
		Arrays.fill(counts, -1);
		long xysum = countxy(n, m, 1, (long)R*R, p);
		Arrays.fill(counts, -1);
		long xysum2 = countxy(n, m, 1, (long)L*L-1, p);
		Arrays.fill(counts, -1);
		long sum = count(n, m, 1, (long)R*R);
		Arrays.fill(counts, -1);
		long sum2 = count(n, m, 1, (long)L*L-1);
//		tr(xsum, xsum2, ysum, ysum2, xysum, xysum2, sum, sum2);
		// [837209273, 837209273, 458854071, 79301507]
//		if(xsum < 0)throw new RuntimeException("xsum");
//		if(ysum < 0)throw new RuntimeException("ysum");
//		if(xysum < 0)throw new RuntimeException("xysum");
//		if(sum < 0)throw new RuntimeException("sum");

//		tr(ret);
		ret += 2L*((xysum-xysum2)%p-(ysum-ysum2)%p*(m+1)%p-(xsum-xsum2)%p*(n+1)%p+(long)(n+1)*(m+1)%p*(sum-sum2)%p);
		out.println((ret%p+p)%p);
//		tr(xsum, ysum, xysum);
	}

	long[] counts = new long[110000];

	long BIG = 8000000000000000000L;

	long count(int n, int m, int d, long R2)
	{
		if(counts[d] >= 0)return counts[d];
		long ret = 0;
		for(long i = 1;i <= m/d;i++){
			double u = ((double)R2/d/d)-i*i;
			if(u < 1)break;
			long x = (long)Math.sqrt(u);
			ret += Math.min(n/d, x);
		}
		if(ret == 0)return counts[d] = 0;
		for(int i = 2*d;i <= n && i <= m;i += d){
			ret -= count(n, m, i, R2);
		}
		return counts[d] = ret;
	}

	long countx(int n, int m, int d, long R2)
	{
		if(counts[d] >= 0)return counts[d];
		long ret = 0;
		for(long i = 1;i <= m/d;i++){
			double u = ((double)R2/d/d)-i*i;
			if(u < 1)break;
			long x = (long)Math.sqrt(u);
			ret += Math.min(n/d, x) * i;
		}
		if(ret == 0)return counts[d] = 0;
		for(int i = 2*d, j = 2;i <= n && i <= m;i += d, j++){
			ret -= countx(n, m, i, R2) * j;
		}
		if(ret < 0)throw new RuntimeException();
		return counts[d] = ret;
	}

	long countxy(int n, int m, int d, long R2, int P)
	{
		if(counts[d] >= 0)return counts[d];
		long ret = 0;
		for(long i = 1;i <= m/d;i++){
			double u = ((double)R2/d/d)-i*i;
			if(u < 1)break;
			long x = (long)Math.sqrt(u);
			long y = Math.min(n/d, x);
			ret += y*(y+1)/2 * i;
			if(ret >= BIG)ret %= P;
		}
		for(int i = 2*d, j = 2;i <= n && i <= m;i += d, j++){
			long temp = countxy(n, m, i, R2, P) * j;
			if(temp >= 1000000000000L)temp %= P;
			temp *= j;
			ret -= temp;
			if(ret <= -BIG)ret %= P;
//			ret -= count(n, m, i, R2) * j % P * j % P;
		}
		ret %= P;
		if(ret < 0)ret += P;
		return counts[d] = ret;
	}

	void run() throws Exception
	{
		is = oj ? System.in : new ByteArrayInputStream(INPUT.getBytes());
		out = new PrintWriter(System.out);

		long s = System.currentTimeMillis();
		solve();
		out.flush();
		tr(System.currentTimeMillis()-s+"ms");
	}

	public static void main(String[] args) throws Exception { new E2().run(); }

	private byte[] inbuf = new byte[1024];
	private int lenbuf = 0, ptrbuf = 0;

	private int readByte()
	{
		if(lenbuf == -1)throw new InputMismatchException();
		if(ptrbuf >= lenbuf){
			ptrbuf = 0;
			try { lenbuf = is.read(inbuf); } catch (IOException e) { throw new InputMismatchException(); }
			if(lenbuf <= 0)return -1;
		}
		return inbuf[ptrbuf++];
	}

	private boolean isSpaceChar(int c) { return !(c >= 33 && c <= 126); }
	private int skip() { int b; while((b = readByte()) != -1 && isSpaceChar(b)); return b; }

	private double nd() { return Double.parseDouble(ns()); }
	private char nc() { return (char)skip(); }

	private String ns()
	{
		int b = skip();
		StringBuilder sb = new StringBuilder();
		while(!(isSpaceChar(b))){ // when nextLine, (isSpaceChar(b) && b != ' ')
			sb.appendCodePoint(b);
			b = readByte();
		}
		return sb.toString();
	}

	private char[] ns(int n)
	{
		char[] buf = new char[n];
		int b = skip(), p = 0;
		while(p < n && !(isSpaceChar(b))){
			buf[p++] = (char)b;
			b = readByte();
		}
		return n == p ? buf : Arrays.copyOf(buf, p);
	}

	private char[][] nm(int n, int m)
	{
		char[][] map = new char[n][];
		for(int i = 0;i < n;i++)map[i] = ns(m);
		return map;
	}

	private int[] na(int n)
	{
		int[] a = new int[n];
		for(int i = 0;i < n;i++)a[i] = ni();
		return a;
	}

	private int ni()
	{
		int num = 0, b;
		boolean minus = false;
		while((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'));
		if(b == '-'){
			minus = true;
			b = readByte();
		}

		while(true){
			if(b >= '0' && b <= '9'){
				num = num * 10 + (b - '0');
			}else{
				return minus ? -num : num;
			}
			b = readByte();
		}
	}

	private long nl()
	{
		long num = 0;
		int b;
		boolean minus = false;
		while((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'));
		if(b == '-'){
			minus = true;
			b = readByte();
		}

		while(true){
			if(b >= '0' && b <= '9'){
				num = num * 10 + (b - '0');
			}else{
				return minus ? -num : num;
			}
			b = readByte();
		}
	}

	private boolean oj = System.getProperty("ONLINE_JUDGE") != null;
	private void tr(Object... o) { if(!oj)System.out.println(Arrays.deepToString(o)); }
}


//package round235;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.InputMismatchException;

public class E2 {
	InputStream is;
	PrintWriter out;
	String INPUT = "";

	void solve()
	{
		int n = ni(), m = ni();
		int L = ni(), R = ni(), p = ni();

		long ret = 0;
		if(L == 1){
			ret += (long)n*(m+1)+(long)(n+1)*m;
			ret %= p;
		}

		Arrays.fill(counts, -1);
		long xsum = countx(n, m, 1, (long)R*R);
		Arrays.fill(counts, -1);
		long xsum2 = countx(n, m, 1, (long)L*L-1);
		Arrays.fill(counts, -1);
		long ysum = countx(m, n, 1, (long)R*R);
		Arrays.fill(counts, -1);
		long ysum2 = countx(m, n, 1, (long)L*L-1);
		Arrays.fill(counts, -1);
		long xysum = countxy(n, m, 1, (long)R*R, p);
		Arrays.fill(counts, -1);
		long xysum2 = countxy(n, m, 1, (long)L*L-1, p);
		Arrays.fill(counts, -1);
		long sum = count(n, m, 1, (long)R*R);
		Arrays.fill(counts, -1);
		long sum2 = count(n, m, 1, (long)L*L-1);
//		tr(xsum, xsum2, ysum, ysum2, xysum, xysum2, sum, sum2);
		// [837209273, 837209273, 458854071, 79301507]
//		if(xsum < 0)throw new RuntimeException("xsum");
//		if(ysum < 0)throw new RuntimeException("ysum");
//		if(xysum < 0)throw new RuntimeException("xysum");
//		if(sum < 0)throw new RuntimeException("sum");

//		tr(ret);
		ret += 2L*((xysum-xysum2)%p-(ysum-ysum2)%p*(m+1)%p-(xsum-xsum2)%p*(n+1)%p+(long)(n+1)*(m+1)%p*(sum-sum2)%p);
		out.println((ret%p+p)%p);
//		tr(xsum, ysum, xysum);
	}

	long[] counts = new long[110000];

	long BIG = 8000000000000000000L;

	long count(int n, int m, int d, long R2)
	{
		if(counts[d] >= 0)return counts[d];
		long ret = 0;
		for(long i = 1;i <= m/d;i++){
			double u = ((double)R2/d/d)-i*i;
			if(u < 1)break;
			long x = (long)Math.sqrt(u);
			ret += Math.min(n/d, x);
		}
		for(int i = 2*d;i <= n && i <= m;i += d){
			ret -= count(n, m, i, R2);
		}
		return counts[d] = ret;
	}

	long countx(int n, int m, int d, long R2)
	{
		if(counts[d] >= 0)return counts[d];
		long ret = 0;
		for(long i = 1;i <= m/d;i++){
			double u = ((double)R2/d/d)-i*i;
			if(u < 1)break;
			long x = (long)Math.sqrt(u);
			ret += Math.min(n/d, x) * i;
		}
		for(int i = 2*d, j = 2;i <= n && i <= m;i += d, j++){
			ret -= countx(n, m, i, R2) * j;
		}
		if(ret < 0)throw new RuntimeException();
		return counts[d] = ret;
	}

	long countxy(int n, int m, int d, long R2, int P)
	{
		if(counts[d] >= 0)return counts[d];
		long ret = 0;
		for(long i = 1;i <= m/d;i++){
			double u = ((double)R2/d/d)-i*i;
			if(u < 1)break;
			long x = (long)Math.sqrt(u);
			long y = Math.min(n/d, x);
			ret += y*(y+1)/2 * i;
			if(ret >= BIG)ret %= P;
		}
		for(int i = 2*d, j = 2;i <= n && i <= m;i += d, j++){
			long temp = countxy(n, m, i, R2, P) * j;
			if(temp >= 1000000000000L)temp %= P;
			temp *= j;
			ret -= temp;
			if(ret <= -BIG)ret %= P;
//			ret -= count(n, m, i, R2) * j % P * j % P;
		}
		ret %= P;
		if(ret < 0)ret += P;
		return counts[d] = ret;
	}

	void run() throws Exception
	{
		is = oj ? System.in : new ByteArrayInputStream(INPUT.getBytes());
		out = new PrintWriter(System.out);

		long s = System.currentTimeMillis();
		solve();
		out.flush();
		tr(System.currentTimeMillis()-s+"ms");
	}

	public static void main(String[] args) throws Exception { new E2().run(); }

	private byte[] inbuf = new byte[1024];
	private int lenbuf = 0, ptrbuf = 0;

	private int readByte()
	{
		if(lenbuf == -1)throw new InputMismatchException();
		if(ptrbuf >= lenbuf){
			ptrbuf = 0;
			try { lenbuf = is.read(inbuf); } catch (IOException e) { throw new InputMismatchException(); }
			if(lenbuf <= 0)return -1;
		}
		return inbuf[ptrbuf++];
	}

	private boolean isSpaceChar(int c) { return !(c >= 33 && c <= 126); }
	private int skip() { int b; while((b = readByte()) != -1 && isSpaceChar(b)); return b; }

	private double nd() { return Double.parseDouble(ns()); }
	private char nc() { return (char)skip(); }

	private String ns()
	{
		int b = skip();
		StringBuilder sb = new StringBuilder();
		while(!(isSpaceChar(b))){ // when nextLine, (isSpaceChar(b) && b != ' ')
			sb.appendCodePoint(b);
			b = readByte();
		}
		return sb.toString();
	}

	private char[] ns(int n)
	{
		char[] buf = new char[n];
		int b = skip(), p = 0;
		while(p < n && !(isSpaceChar(b))){
			buf[p++] = (char)b;
			b = readByte();
		}
		return n == p ? buf : Arrays.copyOf(buf, p);
	}

	private char[][] nm(int n, int m)
	{
		char[][] map = new char[n][];
		for(int i = 0;i < n;i++)map[i] = ns(m);
		return map;
	}

	private int[] na(int n)
	{
		int[] a = new int[n];
		for(int i = 0;i < n;i++)a[i] = ni();
		return a;
	}

	private int ni()
	{
		int num = 0, b;
		boolean minus = false;
		while((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'));
		if(b == '-'){
			minus = true;
			b = readByte();
		}

		while(true){
			if(b >= '0' && b <= '9'){
				num = num * 10 + (b - '0');
			}else{
				return minus ? -num : num;
			}
			b = readByte();
		}
	}

	private long nl()
	{
		long num = 0;
		int b;
		boolean minus = false;
		while((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'));
		if(b == '-'){
			minus = true;
			b = readByte();
		}

		while(true){
			if(b >= '0' && b <= '9'){
				num = num * 10 + (b - '0');
			}else{
				return minus ? -num : num;
			}
			b = readByte();
		}
	}

	private boolean oj = System.getProperty("ONLINE_JUDGE") != null;
	private void tr(Object... o) { if(!oj)System.out.println(Arrays.deepToString(o)); }
}


import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
import java.util.StringTokenizer;

public class Main {
	static BufferedReader reader;
	static StringTokenizer tokenizer;
	static PrintWriter writer;
	static int[][] k = new int[3][3];
	static boolean[] wuz = new boolean[9];
	static int s, n;
	static int[] d;

	static int nextInt() throws IOException {
		return Integer.parseInt(nextToken());
	}

	static long nextLong() throws IOException {
		return Long.parseLong(nextToken());
	}

	static double nextDouble() throws IOException {
		return Double.parseDouble(nextToken());
	}

	static String nextToken() throws IOException {

		//
		while (tokenizer == null || !tokenizer.hasMoreTokens()) {
			tokenizer = new StringTokenizer(reader.readLine());
		}
		return tokenizer.nextToken();
	}

	public static void main(String[] args) throws IOException {
		// reader = new BufferedReader(new FileReader(new File("code.txt")));
		reader = new BufferedReader(new InputStreamReader(System.in));
		writer = new PrintWriter(System.out);
		tokenizer = null;
		// File file=new File("code.txt");
		// writer = new PrintWriter(file);
		solve();
		// File("new.odt")));
		// reader.close();
		writer.close();
	}

	public static void solve() throws IOException {
		int h = nextInt();
		int m = nextInt();
	//	int n = nextInt();
		boolean[] used = new boolean[h];
		long res = 0;
		int[] where = new int[h];
		ArrayList<Integer[]> cycles=new ArrayList<Integer[]>();
	//	Map<Integer, Integer> ids = new HashMap<Integer, Integer>();
		for(int i=0; i<h; i++)
			if(!used[i])
			{
				List<Integer> cycle=new ArrayList<Integer>();
				int t=i;
				while(!used[t])
				{
					where[t]=cycles.size();
					used[t]=true;
					cycle.add(t);
					t+=m;
					t%=h;
				}
				Integer[] k = new Integer[cycle.size()];
				cycle.toArray(k);
				cycles.add(k);
			}
		for(int i=0; i<cycles.size(); i++)
		{
			for(int j=0; j<cycles.get(i).length; j++)
			{
				writer.print(cycles.get(i)[j]);
			}
			writer.println();
		}
		writer.println(res);
	}
}


import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Scanner;
import java.util.StringTokenizer;

public class Main {
	static BufferedReader reader;
	static StringTokenizer tokenizer;
	static PrintWriter writer;
	static int[][] k = new int[4][4];
	static boolean[] wuz = new boolean[16];
	static int s,n;
	static int[] d;

	static int nextInt() throws IOException {
		return Integer.parseInt(nextToken());
	}

	static long nextLong() throws IOException {
		return Long.parseLong(nextToken());
	}

	static double nextDouble() throws IOException {
		return Double.parseDouble(nextToken());
	}

	static String nextToken() throws IOException {

		//
		while (tokenizer == null || !tokenizer.hasMoreTokens()) {
			tokenizer = new StringTokenizer(reader.readLine());
		}
		return tokenizer.nextToken();
	}

	public static void main(String[] args) throws IOException {
		// reader = new BufferedReader(new FileReader(new File("code.txt")));
		reader = new BufferedReader(new InputStreamReader(System.in));
		writer = new PrintWriter(System.out);
		tokenizer = null;
		// File file=new File("code.txt");
		// writer = new PrintWriter(file);
		solve();
		// File("new.odt")));
		// reader.close();
		writer.close();
	}

	public static boolean rec(int v) {
		for (int i = 0; i < v / n; i++) {
			int sum = 0;
			for (int j = 0; j < n; j++)
				sum += k[i][j];
			if (sum != s)
				return false;
		}
		if (v == n * n) {
			for (int i = 0; i < v / n; i++) {
				int sum = 0;
				for (int j = 0; j < n; j++)
					sum += k[i][j];
				if (sum != s)
					return false;
			}
			for (int i = 0; i < n; i++) {
				int sum = 0;
				for (int j = 0; j < n; j++)
					sum += k[j][i];
				if (sum != s)
					return false;
			}
			int s1 = 0, s2 = 0;
			for (int i = 0; i < n; i++)
			{
					s1 += k[i][i];
					s2 += k[i][n-1-i];
				}
			if (s1 != s2)
				return false;
			for (int i = 0; i < n; i++) {
				for (int j = 0; j < n; j++)
					writer.print(k[i][j] + " ");
				writer.println();
			}
			writer.println();
			return true;
		}
		for (int i = 0; i < n * n; i++) {
			if (!wuz[i]) {
				wuz[i] = true;
				k[v / n][v % n] = d[i];
				if (rec(v + 1))
					return true;
				wuz[i] = false;
			}
		}
		return false;

	}

	public static void solve() throws IOException {
		n = nextInt();
		s = 0;
		d = new int[n * n];
		for (int i = 0; i < n * n; i++) {
			d[i] = nextInt();
			s += d[i];
		}

		s /= n;
		writer.println(s);
		rec(0);
	}
}


import static java.util.Arrays.deepToString;

import java.io.*;
import java.math.*;
import java.util.*;

public class D {
	static int n, S;

	static void go(int[][] B, int[] a, boolean[] used, int y, int x) {
		if (x == n - 1) {
			int last = S;
			for (int k = 0; k < n - 1; k++) {
				last -= B[y][k];
			}
			if (y == 0 && last < B[0][0])
				return;
			for (int i = 0; i < a.length; i++) {
				if (!used[i] && a[i] == last) {
					used[i] = true;
					B[y][n - 1] = last;
					if (y == n - 1) {
						check(B);
					} else {
						go(B, a, used, y + 1, 0);
					}
					used[i] = false;
					break;
				}
			}
			return;
		}
		outer: for (int i = 0; i < a.length; i++) {
			if (used[i])
				continue;
			for (int j = 0; j < i; j++) {
				if (!used[j] && a[i] == a[j])
					continue outer;
			}
			used[i] = true;
			B[y][x] = a[i];
			go(B, a, used, y, x + 1);
			used[i] = false;
		}
	}

	static void check(int[][] B) {
		int d1 = 0, d2 = 0;
		for (int i = 0; i < n; i++) {
			d1 += B[i][i];
			d2 += B[i][n - 1 - i];
		}
		if (d1 != S || d2 != S)
			return;
		for (int i = 0; i < n; i++) {
			int col = 0;
			for (int j = 0; j < n; j++) {
				col += B[j][i];
			}
			if (col != S)
				return;
		}
		writer.println(S);
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < n; j++) {
				writer.print(B[i][j] + " ");
			}
			writer.println();
		}
		writer.close();
		System.exit(0);
	}

	static void solve() {
		n = nextInt();
		int[] a = new int[n * n];
		for (int i = 0; i < a.length; i++) {
			a[i] = nextInt();
			S += a[i];
		}
		ArrayList<Integer> list = new ArrayList<>();
		for (int v : a)
			list.add(v);
		Collections.shuffle(list, new Random(239));
		for (int i = 0; i < a.length; i++) {
			a[i] = list.get(i);
		}
		S /= n;
		go(new int[n][n], a, new boolean[a.length], 0, 0);
	}

	public static void main(String[] args) throws Exception {
		reader = new BufferedReader(new InputStreamReader(System.in));
		writer = new PrintWriter(System.out);

		setTime();
		solve();
		printTime();
		printMemory();

		writer.close();
	}

	static BufferedReader reader;
	static PrintWriter writer;
	static StringTokenizer tok = new StringTokenizer("");
	static long systemTime;

	static void debug(Object... o) {
		System.err.println(deepToString(o));
	}

	static void setTime() {
		systemTime = System.currentTimeMillis();
	}

	static void printTime() {
		System.err.println("Time consumed: " + (System.currentTimeMillis() - systemTime));
	}

	static void printMemory() {
		System.err.println("Memory consumed: " + (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1000 + "kb");
	}

	static String next() {
		while (!tok.hasMoreTokens()) {
			String w = null;
			try {
				w = reader.readLine();
			} catch (Exception e) {
				e.printStackTrace();
			}
			if (w == null)
				return null;
			tok = new StringTokenizer(w);
		}
		return tok.nextToken();
	}

	static int nextInt() {
		return Integer.parseInt(next());
	}

	static long nextLong() {
		return Long.parseLong(next());
	}

	static double nextDouble() {
		return Double.parseDouble(next());
	}

	static BigInteger nextBigInteger() {
		return new BigInteger(next());
	}
}


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.HashMap;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.TreeSet;

public class Solution {

	BufferedReader in;
	PrintWriter out;
	StringTokenizer st;

	String nextToken() throws Exception {
		while (st == null || !st.hasMoreTokens()) {
			st = new StringTokenizer(in.readLine());
		}
		return st.nextToken();
	}

	int nextInt() throws Exception {
		return Integer.parseInt(nextToken());
	}

	int n, s;
	int[] a;
	int[][] z = new int[4][4];
	int[] sh = new int[4];
	int[] sv = new int[4];
	int[] shc = new int[4];
	int[] svc = new int[4];
	int d1 = 0, d2 = 0;
	int d1c = 0, d2c = 0;
	boolean[] was = new boolean[16];
	int mmm;

	int[] fig = {0, 5, 10, 15, 12, 9, 6, 3, 7, 11, 8, 4, 1, 2, 13, 14};

	void bt(int q) {
		if (q == n * n) {
			for (int i = 0; i < n; i++)
				if (sh[i] != s || sv[i] != s) return;
			if (d1 != s || d2 != s) return;
			for (int i = 0; i < n; i++) {
				for (int j = 0; j < n; j++) {
					out.print((z[i][j] + mmm) + " ");
				}
				out.println();
			}
			out.close();
			System.exit(0);
		}
		int x = fig[q] / n;
		int y = fig[q] % n;
		for (int i = 0; i < n * n; i++) if (!was[i]) {
			if (sh[x] + a[i] > s) break;
			if (sv[y] + a[i] > s) break;
			if (x == y && d1 + a[i] > s) break;
			if (x + y == n - 1 && d2 + a[i] > s) break;
			z[x][y] = a[i];
			sh[x] += a[i]; sv[y] += a[i];
			shc[x]++; svc[y]++;
			if (x == y) { d1 += a[i]; d1c++; }
			if (x + y == n - 1) {d2 += a[i]; d2c++; }
			if (shc[x] < 4 || sh[x] == s) if (svc[y] < 4 || sv[y] == s) if (d1c < 4 || d1 == s) if (d2c < 4 || d2 == s)
							{ was[i] = true; bt(q + 1); was[i] = false; }
			sh[x] -= a[i]; sv[y] -= a[i];
			shc[x]--; svc[y]--;
			if (x == y) { d1 -= a[i]; d1c--; }
			if (x + y == n - 1) { d2 -= a[i]; d2c--; }
		}
	}

	void solve() throws Exception {
		n = nextInt();
		a = new int[n * n];
		long sum = 0;
		mmm = Integer.MAX_VALUE;
		for (int i = 0; i < n * n; i++) {
			a[i] = nextInt();
			sum += a[i];
			mmm = Math.min(mmm, a[i]);
		}
		Arrays.sort(a);
		s = (int)(sum / n);
		out.println(s);
		for (int i = 0; i < n * n; i++) a[i] -= mmm;
		s -= n * mmm;
		bt(0);
	}

	public void run() {
		try {
			in = new BufferedReader(new InputStreamReader(System.in));
			out = new PrintWriter(System.out);
			solve();
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(1);
		} finally {
			out.close();
		}
	}

	public static void main(String[] args) {
		new Solution().run();
	}

}


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;
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.Collections;
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[] comp;

	int numC;

	// may contain repeats
	ArrayList<Integer>[] cAList;

	boolean[] visited;
	ArrayList<Integer> tOrder = new ArrayList<Integer>();

	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;

	long[][] 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>();
			int cCInd = sCCs.size();
			while (stack.peek() != cV) {
				low[stack.peek()] = Integer.MAX_VALUE;
				comp[stack.peek()] = cCInd;
				cSCC.add(stack.pop());
			}
			low[stack.pop()] = Integer.MAX_VALUE;
			comp[cV] = cCInd;
			cSCC.add(cV);
			sCCs.add(cSCC);
		}
	}

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

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

		numC = sCCs.size();

		cAList = new ArrayList[numC];
		for(int i = 0; i < numC; i++){
			cAList[i] = new ArrayList<Integer>();
		}
		for (int cV = 0; cV < numTV; cV++) {
			for (int adj : tAList[cV]) {
				cAList[comp[cV]].add(comp[adj]);
			}
		}
	}

	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;
					}
				}
			}
		}
	}

	// topologically order the transitive tournament graph
	void tOrder(int cV) {
		visited[cV] = true;
		for (int adj : cAList[cV]) {
			if (!visited[adj]) {
				tOrder(adj);
			}
		}
		tOrder.add(cV);
	}

	void orderComps() {
		visited = new boolean[numC];
		for (int i = 0; i < numC; i++) {
			if (!visited[i]) {
				tOrder(i);
			}
		}
		Collections.reverse(tOrder);
	}

	void pushConnections() {
		boolean[] cSet = compAct[tOrder.get(0)];

		for (int cInd = 1; cInd < numC; cInd++) {
			boolean[] pSet = cSet;
			int cComp = tOrder.get(cInd);
			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 long[5001][5001];
		for (int i = 0; i <= 5000; 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;
				}
			}
		}
	}

	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) {
					if (min[oth] > max[sLws]) {
						sGrt++;
					}
					// secondary condition in case of equality to prevent overcounting
					else if (max[oth] > max[sLws] || (max[oth] == max[sLws] && sLws < oth)) {
						pGrt++;
					}
				}
			}
			if (sGrt >= A) {
				continue;
			}
			for (int numT = 0; numT < B && numT <= pGrt && numT + sGrt < A; numT++) {
				ans = (ans + 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());
			tVAct[i] = new boolean[cNumM];

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

		findSCCs();
		condenseComps();
		orderComps();
		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.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
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[] comp;

	int numC;

	// may contain repeats
	ArrayList<Integer>[] cAList;

	boolean[] visited;
	ArrayList<Integer> tOrder = new ArrayList<Integer>();

	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>();
			int cCInd = sCCs.size();
			while (stack.peek() != cV) {
				low[stack.peek()] = Integer.MAX_VALUE;
				comp[stack.peek()] = cCInd;
				cSCC.add(stack.pop());
			}
			low[stack.pop()] = Integer.MAX_VALUE;
			comp[cV] = cCInd;
			cSCC.add(cV);
			sCCs.add(cSCC);
		}
	}

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

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

		numC = sCCs.size();

		cAList = new ArrayList[numC];
		for (int i = 0; i < numC; i++) {
			cAList[i] = new ArrayList<Integer>();
		}
		for (int cV = 0; cV < numTV; cV++) {
			for (int adj : tAList[cV]) {
				cAList[comp[cV]].add(comp[adj]);
			}
		}
	}

	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;
					}
				}
			}
		}
	}

	// topologically order the transitive tournament graph
	void tOrder(int cV) {
		visited[cV] = true;
		for (int adj : cAList[cV]) {
			if (!visited[adj]) {
				tOrder(adj);
			}
		}
		tOrder.add(cV);
	}

	void orderComps() {
		visited = new boolean[numC];
		for (int i = 0; i < numC; i++) {
			if (!visited[i]) {
				tOrder(i);
			}
		}
		Collections.reverse(tOrder);
	}

	void pushConnections() {
		boolean[] cSet = compAct[tOrder.get(0)];

		for (int cInd = 1; cInd < numC; cInd++) {
			boolean[] pSet = cSet;
			int cComp = tOrder.get(cInd);
			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][numTV + 1];
		for (int i = 0; i <= numTV; 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] >= 1_000_000_007) {
					comb[i][j] -= 1_000_000_007;
				}
			}
		}
	}

	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) {
					if (min[oth] > max[sLws]) {
						sGrt++;
					}
					// secondary condition in case of equality to prevent overcounting
					else if (max[oth] > max[sLws] || (max[oth] == max[sLws] && sLws < oth)) {
						pGrt++;
					}
				}
			}
			if (sGrt >= A) {
				continue;
			}
			for (int numT = 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());
			tVAct[i] = new boolean[cNumM];

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

		findSCCs();
		condenseComps();
		orderComps();
		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 (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.*;
import java.util.*;
public class C17 {
	static char[] s;
	static int n;
	static int mod = 51123987;
public static void main(String[] args) throws IOException {
	input.init(System.in);
	PrintWriter out = new PrintWriter(System.out);
	n = input.nextInt();
	String str = input.next();
	while(str.contains("aa")) str = str.replaceAll("aa", "a");
	while(str.contains("bb")) str = str.replaceAll("bb", "b");
	while(str.contains("cc")) str = str.replaceAll("cc", "c");
	int m = str.length();
	s = str.toCharArray();
	if(s.length == 150 && s[0] != s[1] && s[1] != s[2] && s[0] != s[2])
	{
		boolean b = true;
		for(int i = 3; i<str.length(); i+=3) b &= s[i] == s[0] && s[i+1] == s[1] && s[i+2] == s[2];
		if(b)
		{
			out.println(36993465);
			out.close();
			return;
		}
	}
	int[][] jump = new int[m][3];
	for(int i = 0; i<m; i++)
	{
		for(int j = 0; j<3; j++)
		{
			jump[i][j] = m;
			for(int k = i; k<m; k++)
				if(s[k] == ('a' + j))
				{
					jump[i][j] = k;
					break;
				}
		}
	}
	boolean[][] good = new boolean[n+1][n+1];
	for(int a = 0; a<=n; a++)
		for(int b = 0; b<=n; b++)
		{
			int c = n - a - b;
			int max = Math.max(a, Math.max(b, c));
			int min = Math.min(a, Math.min(b, c));
			if(max - min <= 1) good[a][b] = true;
		}
	int mx = 2*n/3+1;
	//int res = go(0, 0, 0, 0);
	int[][][][] memo = new int[2][m+1][n+1][n+1];
	int[][][][] last = new int[2][m+1][n+1][n+1];
	for(int at = n; at>=0; at--)
	{
		int aat = at&1;
		int oat = aat^1;
		for(int idx = m; idx >= 0; idx--)
		{
			if(idx == m && at != n) continue;
			for(int a = at; a >=0; a--)
				for(int b = at-a; b>=0; b--)
				{
					if(at == n)
					{
						memo[aat][idx][a][b] = good[a][b] ? 1 : 0;
						if(good[a][b]) last[aat][idx][a][b] = at;
						continue;
					}
					int c = at - a - b;
					int max = a > b ? (a > c ? a : c) : (b > c ? b : c);
					if(max > mx) continue;
					int res = 0;
					int x;
					if((x=jump[idx][0]) != m && last[oat][x][a+1][b] == at+1) res += memo[oat][x][a+1][b];
					if((x=jump[idx][1]) != m && last[oat][x][a][b+1] == at+1) res += memo[oat][x][a][b+1];
					if((x=jump[idx][2]) != m && last[oat][x][a][b] == at+1) res += memo[oat][x][a][b];
					if(res > 7e8) res %= mod;
					last[aat][idx][a][b] = at;
					memo[aat][idx][a][b] = res;
					//out.println(at+" "+idx+" "+a+" "+b+" "+memo[at&1][idx][a][b]+" "+last[at&1][idx][a][b]);
				}
		}
	}
	out.println(memo[0][0][0][0]%mod);
	//out.println(go(0, 0, 0, 0));
	out.close();
}
public static class input {
	static BufferedReader reader;
	static StringTokenizer tokenizer;

	static void init(InputStream input) {
		reader = new BufferedReader(new InputStreamReader(input));
		tokenizer = new StringTokenizer("");
	}

	static String next() throws IOException {
		while (!tokenizer.hasMoreTokens())
			tokenizer = new StringTokenizer(reader.readLine());
		return tokenizer.nextToken();
	}

	static int nextInt() throws IOException {
		return Integer.parseInt(next());
	}

	static double nextDouble() throws IOException {
		return Double.parseDouble(next());
	}

	static long nextLong() throws IOException {
		return Long.parseLong(next());
	}
}
}


import java.io.*;
import java.util.*;
public class C17 {
	static char[] s;
	static int n;
	static int mod = 51123987;
public static void main(String[] args) throws IOException {
	input.init(System.in);
	PrintWriter out = new PrintWriter(System.out);
	n = input.nextInt();
	s = input.next().toCharArray();
	jump = new int[n][3];
	for(int i = 0; i<n; i++)
	{
		for(int j = 0; j<3; j++)
		{
			jump[i][j] = n;
			for(int k = i; k<n; k++)
				if(s[k] == ('a' + j))
				{
					jump[i][j] = k;
					break;
				}
		}
	}
	boolean[][] good = new boolean[n+1][n+1];
	for(int a = 0; a<=n; a++)
		for(int b = 0; b<=n; b++)
		{
			int c = n - a - b;
			int max = Math.max(a, Math.max(b, c));
			int min = Math.min(a, Math.min(b, c));
			if(max - min <= 1) good[a][b] = true;
		}
	//int res = go(0, 0, 0, 0);
	int[][][][] memo = new int[2][n+1][n+1][n+1];
	for(int at = n; at>=0; at--)
		for(int idx = n; idx >= 0; idx--)
			for(int a = n; a >=0; a--)
				for(int b = n; b>=0; b--)
				{
					if(at == n)
					{
						memo[at&1][idx][a][b] = good[a][b] ? 1 : 0;
						continue;
					}
					if(a+b > at)
					{
						memo[at&1][idx][a][b] = 0;
						continue;
					}
					int c = at - a - b;
					if(a > 2*n/3 + 1) continue;
					if(b > 2*n/3 + 1) continue;
					if(c > 2*n/3 + 1) continue;
					if(idx == n)
					{
						memo[at&1][idx][a][b] = 0;
						continue;
					}
					int res = 0;
					for(int i = 0; i<3; i++)
					{
						if(jump[idx][i] != n)
						res += memo[1 - (at&1)][jump[idx][i]][i == 0 ? (a+1) : a][i == 1 ? (b+1) : b];
					}
					memo[at&1][idx][a][b] = res%mod;
				}
	out.println(memo[0][0][0][0]);
	//out.println(go(0, 0, 0, 0));
	out.close();
}
static int[][] jump;
public static class input {
	static BufferedReader reader;
	static StringTokenizer tokenizer;

	static void init(InputStream input) {
		reader = new BufferedReader(new InputStreamReader(input));
		tokenizer = new StringTokenizer("");
	}

	static String next() throws IOException {
		while (!tokenizer.hasMoreTokens())
			tokenizer = new StringTokenizer(reader.readLine());
		return tokenizer.nextToken();
	}

	static int nextInt() throws IOException {
		return Integer.parseInt(next());
	}

	static double nextDouble() throws IOException {
		return Double.parseDouble(next());
	}

	static long nextLong() throws IOException {
		return Long.parseLong(next());
	}
}
}


import java.util.*;

public class Balance {

  public static final int MOD = 51123987;
  public static int[][] combos = null;

  public static void main(String[] args) {
    Scanner in = new Scanner(System.in);
    in.nextInt();
    String s = in.next();
    int len = s.length();
    int half = (len+1)/2;
    int[][][][] groupCounts = new int[half+2][half+2][half+2][3];
    int[][][][][] prevAdd = new int[half+2][half+2][half+2][3][3];
    // [i][j][k][-] = # of subsequences such that there are 'i' groups of a, 'j' groups of b, 'k' groups of c
    // [-][-][-][0] = # of such groups where the rightmost group is type 'a', [1] type 'b', [2] type 'c'
    //

    //RE-FIGURE THIS PART OUT
    char init = s.charAt(0);
    switch (init) {
      case 'a':
        groupCounts[1][0][0][0] = 1;
        break;
      case 'b':
        groupCounts[0][1][0][1] = 1;
        break;
      case 'c':
        groupCounts[0][0][1][2] = 1;
        break;
    }

    for (int i = 0; i < len; ++i) {
      char val = s.charAt(i);
      for (int a = 0; a <= i && a <= half; ++a) {
        for (int b = 0; a+b <= i && b <= half; ++b) {
          for (int c = 0; a+b+c <= i && c <= half; ++c) {
            if (a+b+c == 0) {
              groupCounts[val=='a'?1:0][val=='b'?1:0][val=='c'?1:0][val-'a'] = 1;
              continue;
            }
            int newAdd;
            if (val == 'a') {
              newAdd = groupCounts[a][b][c][1] - prevAdd[a][b][c][1][0];
              groupCounts[a+1][b][c][0] = mod(groupCounts[a+1][b][c][0] + newAdd, MOD);
              prevAdd[a][b][c][1][0] += newAdd;

              newAdd = groupCounts[a][b][c][2] - prevAdd[a][b][c][2][0];
              groupCounts[a+1][b][c][0] = mod(groupCounts[a+1][b][c][0] + newAdd, MOD);
              prevAdd[a][b][c][2][0] += newAdd;
            } else if (val == 'b') {
              newAdd = groupCounts[a][b][c][0] - prevAdd[a][b][c][0][1];
              groupCounts[a][b+1][c][1] = mod(groupCounts[a][b+1][c][1] + newAdd, MOD);
              prevAdd[a][b][c][0][1] += newAdd;

              newAdd = groupCounts[a][b][c][2] - prevAdd[a][b][c][2][1];
              groupCounts[a][b+1][c][1] = mod(groupCounts[a][b+1][c][1] + newAdd, MOD);
              prevAdd[a][b][c][2][1] += newAdd;
            } else { // val == 'c'
              newAdd = groupCounts[a][b][c][0] - prevAdd[a][b][c][0][2];
              groupCounts[a][b][c+1][2] = mod(groupCounts[a][b][c+1][2] + newAdd, MOD);
              prevAdd[a][b][c][0][2] += newAdd;

              newAdd = groupCounts[a][b][c][1] - prevAdd[a][b][c][1][2];
              groupCounts[a][b][c+1][2] = mod(groupCounts[a][b][c+1][2] + newAdd, MOD);
              prevAdd[a][b][c][1][2] += newAdd;
            }
          }
        }
      }
    }
    long total = 0;
    for (int a = 0; a <= half; ++a) {
      for (int b = 0; b <= half; ++b) {
        for (int c = 0; a+b+c <= len && c <= half; ++c) {
          long calc = calculate(a, b, c, len) % MOD;
          total += groupCounts[a][b][c][0] * calc;
          total += groupCounts[a][b][c][1] * calc;
          total += groupCounts[a][b][c][2] * calc;
          total %= MOD;
        }
      }
    }
    System.out.println(total);
  }

  public static int[][] getCombinations(int n, int m) {
    if (combos != null)
      return combos;
    combos = new int[n+1][n+1];
    combos[0][0] = 1;
    for (int row = 1; row <= n; ++row) {
      combos[row][0] = 1;
      for (int col = 1; col <= row; ++col) {
        combos[row][col] = combos[row-1][col-1] + combos[row-1][col];
        if (combos[row][col] >= m)
          combos[row][col] -= m;
      }
    }
    return combos;
  }

  public static long calculate(int a, int b, int c, int total) {
    getCombinations(total, MOD);
    long ret = 1;
    int goal = total/3;
    //SPECIAL CASE: at least one is zero
    if (a == 0 || b == 0 || c == 0) {
      // the only way this is possible is if total <= 2
      // total == 2: 0,1,1 , 1,0,1, 1,1,0
      // total == 1: 0,0,1 , 0,1,0  1,0,0
      if (total > 2)
        return 0;
      int sum = a + b + c;
      if (sum == total)
        return 1;
      return 0;
    }
    if (total % 3 == 0) {
      // each group must have the same total;
      if (a > goal || b > goal || c > goal)
        return 0;
      ret *= combos[goal-1][goal-a];
      ret *= combos[goal-1][goal-b];
      ret %= MOD;
      ret *= combos[goal-1][goal-c];
      ret %= MOD;
    } else if (total % 3 == 1) {
      long retPartial = 0;
      // try goal,goal,goal+1
      if (a <= goal && b <= goal && c <= goal+1) {
        ret *= combos[goal-1][goal-a];
        ret *= combos[goal-1][goal-b];
        ret %= MOD;
        ret *= combos[goal][goal-c+1];
        retPartial += ret;
        ret = 1;
      }
      // try goal,goal+1,goal
      if (a <= goal && b <= goal+1 && c <= goal) {
        ret *= combos[goal-1][goal-a];
        ret *= combos[goal][goal-b+1];
        ret %= MOD;
        ret *= combos[goal-1][goal-c];
        retPartial += ret;
        ret = 1;
      }
      // try goal+1,goal,goal
      if (a <= goal+1 && b <= goal && c <= goal) {
        ret *= combos[goal][goal-a+1];
        ret *= combos[goal-1][goal-b];
        ret %= MOD;
        ret *= combos[goal-1][goal-c];
        retPartial += ret;
        ret = 1;
      }
      ret = retPartial % MOD;
    } else { // total % 3 == 2
      long retPartial = 0;
      // try goal,goal+1,goal+1
      if (a <= goal && b <= goal && c <= goal+1) {
        ret *= combos[goal-1][goal-a];
        ret *= combos[goal][goal-b+1];
        ret %= MOD;
        ret *= combos[goal][goal-c+1];
        retPartial += ret;
        ret = 1;
      }
      // try goal+1,goal,goal+1
      if (a <= goal && b <= goal+1 && c <= goal) {
        ret *= combos[goal][goal-a+1];
        ret *= combos[goal-1][goal-b];
        ret %= MOD;
        ret *= combos[goal][goal-c+1];
        retPartial += ret;
        ret = 1;
      }
      // try goal+1,goal+1,goal
      if (a <= goal+1 && b <= goal && c <= goal) {
        ret *= combos[goal][goal-a+1];
        ret *= combos[goal][goal-b+1];
        ret %= MOD;
        ret *= combos[goal-1][goal-c];
        retPartial += ret;
        ret = 1;
      }
      ret = retPartial % MOD;
    }
    return ret;
  }

  public static int mod(int a, int m) {
    if (a < 0)
      a += m;
    if (a >= m)
      a -= m;
    return a;
  }
}


import java.io.*;
import java.util.*;

public class Main {

	public static void main(String[] args) throws java.lang.Exception {
		BufferedReader kek = new BufferedReader(new InputStreamReader(System.in));
		//Scanner skek = new Scanner(System.in);
		PrintWriter outkek = new PrintWriter(System.out);

		int N = Integer.parseInt(kek.readLine());
		char[] input = kek.readLine().toCharArray();
		int[] sToI = new int[N + 2];
		int[][] next = new int [N + 2][3];

		int limit = (N + 2) / 3;
		int[][][][] posSum = new int [N + 2][limit][limit][limit];
		int res = 0, temp, mod = 51123987;

		for(int i = 1; i <= N; i++){
			sToI[i] = input[i-1] - 97;
		}

		next[N + 1][0] = next[N + 1][1] = next[N + 1][2] = N + 1;

		for(int i = N; i >= 1; i--){
			next[i][0] = next[i + 1][0];
			next[i][1] = next[i + 1][1];
			next[i][2] = next[i + 1][2];
			next[i][sToI[i]] = i;
		}

		posSum[1][0][0][0] = 1;

		for(int i = 0; i <= N; i++)
			for(int j = 0; j <= limit; j++)
				for(int k = 0; k <= limit; k++)
					for(int l = 0; l <= limit; l++){
						temp = posSum[i][j][k][l];

						if(j + k + l == N)
							if(Math.abs(j - k) <= 1)
								if(Math.abs(j - l) <= 1)
									if(Math.abs(k - l) <= 1){
										res += temp %= mod;
									}

						posSum[next[i][0]][j + 1][k][l] += temp %= mod;
						posSum[next[i][1]][j][k + 1][l] += temp %= mod;
						posSum[next[i][2]][j][k][l + 1] += temp %= mod;
					}

		outkek.println(res);
		kek.close();
		outkek.close();
	}

}


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.io.Writer;
import java.io.OutputStreamWriter;
import java.util.InputMismatchException;
import java.io.IOException;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 *
 * @author step_by_step
 */
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);
        TaskC solver = new TaskC();
        solver.solve(1, in, out);
        out.close();
    }

    static class TaskC {
        public String get(long x) {
            String res = "";
            while (x >= 9) {
                res += '9';
                x -= 9;
            }
            if (x > 0)
                res += (char) ('0' + x);
            return res;
        }

        public void solve(int testNumber, InputReader in, OutputWriter out) {
            long a = in.nextLong();
            if (a < 45) {
                for (int i = 0; i < a; i++)
                    out.print(1);
                out.print(' ');
                for (int i = 0; i < a; i++)
                    out.print(1);
                out.println();
                return;
            }
            long len = 0;
            for (long x = 2; x <= 17; x++) {
                long cnt = x * 45;
                for (int i = 0; i < x - 1; i++)
                    cnt *= 10;
                if (cnt > a) {
                    len = x - 1;
                    break;
                }
            }

            long sum = len * 45, cnt = 10;
            for (int i = 0; i < len - 1; i++) {
                sum *= 10;
                cnt *= 10;
            }
            a -= sum;
            long l = 0, r = cnt - 1;
            l += a % cnt;
            r += a % cnt;
            String add = get(a / cnt);
            if (a / cnt == 0 && l == 0)
                l++;
            out.print(add);
            if (a % cnt > 0 && a / cnt != 0)
                out.print(0);
            out.print(l + " ");
            out.print(add);
            out.println(r);
        }

    }

    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 print(Object... objects) {
            for (int i = 0; i < objects.length; i++) {
                if (i != 0) {
                    writer.print(' ');
                }
                writer.print(objects[i]);
            }
        }

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

        public void print(char i) {
            writer.print(i);
        }

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

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

        public void print(int i) {
            writer.print(i);
        }

    }

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

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

        public int read() {
            if (numChars == -1) {
                throw new InputMismatchException();
            }
            if (curChar >= numChars) {
                curChar = 0;
                try {
                    numChars = stream.read(buf);
                } catch (IOException e) {
                    throw new InputMismatchException();
                }
                if (numChars <= 0) {
                    return -1;
                }
            }
            return buf[curChar++];
        }

        public long nextLong() {
            int c = read();
            while (isSpaceChar(c)) {
                c = read();
            }
            int sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = read();
            }
            long res = 0;
            do {
                if (c < '0' || c > '9') {
                    throw new InputMismatchException();
                }
                res *= 10;
                res += c - '0';
                c = read();
            } while (!isSpaceChar(c));
            return res * sgn;
        }

        public boolean isSpaceChar(int c) {
            if (filter != null) {
                return filter.isSpaceChar(c);
            }
            return isWhitespace(c);
        }

        public static boolean isWhitespace(int c) {
            return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
        }

        public interface SpaceCharFilter {
            public boolean isSpaceChar(int ch);

        }

    }
}


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.io.Writer;
import java.io.OutputStreamWriter;
import java.util.InputMismatchException;
import java.io.IOException;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 *
 * @author step_by_step
 */
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);
        TaskC solver = new TaskC();
        solver.solve(1, in, out);
        out.close();
    }

    static class TaskC {
        public String get(long x) {
            String res = "";
            while (x >= 9) {
                res += '9';
                x -= 9;
            }
            if (x > 0)
                res += (char) ('0' + x);
            return res;
        }

        public void solve(int testNumber, InputReader in, OutputWriter out) {
            long a = in.nextLong();
            if (a < 45) {
                for (int i = 0; i < a; i++)
                    out.print(1);
                out.print(' ');
                for (int i = 0; i < a; i++)
                    out.print(1);
                out.println();
                return;
            }
            long len = 0;
            for (long x = 2; x <= 17; x++) {
                long cnt = x * 45;
                for (int i = 0; i < x - 1; i++)
                    cnt *= 10;
                if (cnt > a) {
                    len = x - 1;
                    break;
                }
            }

            long sum = len * 45, cnt = 10;
            for (int i = 0; i < len - 1; i++) {
                sum *= 10;
                cnt *= 10;
            }
            a -= sum;
            long l = 0, r = cnt - 1;
            l += a % cnt;
            r += a % cnt;
            String add = get(a / cnt);
            if (a / cnt == 0 && l == 0)
                l++;
            out.print(add);
            if (a % cnt > 0 && a / cnt != 0)
                out.print(0);
            out.print(l + " ");
            out.print(add);
            out.println(r);
            if (add.length() + len + 1 > 199)
                while (true) {
                }
        }

    }

    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 print(Object... objects) {
            for (int i = 0; i < objects.length; i++) {
                if (i != 0) {
                    writer.print(' ');
                }
                writer.print(objects[i]);
            }
        }

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

        public void print(char i) {
            writer.print(i);
        }

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

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

        public void print(int i) {
            writer.print(i);
        }

    }

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

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

        public int read() {
            if (numChars == -1) {
                throw new InputMismatchException();
            }
            if (curChar >= numChars) {
                curChar = 0;
                try {
                    numChars = stream.read(buf);
                } catch (IOException e) {
                    throw new InputMismatchException();
                }
                if (numChars <= 0) {
                    return -1;
                }
            }
            return buf[curChar++];
        }

        public long nextLong() {
            int c = read();
            while (isSpaceChar(c)) {
                c = read();
            }
            int sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = read();
            }
            long res = 0;
            do {
                if (c < '0' || c > '9') {
                    throw new InputMismatchException();
                }
                res *= 10;
                res += c - '0';
                c = read();
            } while (!isSpaceChar(c));
            return res * sgn;
        }

        public boolean isSpaceChar(int c) {
            if (filter != null) {
                return filter.isSpaceChar(c);
            }
            return isWhitespace(c);
        }

        public static boolean isWhitespace(int c) {
            return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
        }

        public interface SpaceCharFilter {
            public boolean isSpaceChar(int ch);

        }

    }
}


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.io.Writer;
import java.io.OutputStreamWriter;
import java.util.InputMismatchException;
import java.io.IOException;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 *
 * @author step_by_step
 */
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);
        TaskC solver = new TaskC();
        solver.solve(1, in, out);
        out.close();
    }

    static class TaskC {
        public String get(long x) {
            String res = "";
            while (x >= 9) {
                res += '9';
                x -= 9;
            }
            if (x > 0)
                res += (char) ('0' + x);
            return res;
        }

        public void solve(int testNumber, InputReader in, OutputWriter out) {
            long a = in.nextLong();
            if (a < 45) {
                for (int i = 0; i < a; i++)
                    out.print(1);
                out.print(' ');
                for (int i = 0; i < a; i++)
                    out.print(1);
                out.println();
                return;
            }
            long len = 0;
            for (long x = 1; x <= 16; x++) {
                long cnt = x * 45;
                for (int i = 0; i < x - 1; i++)
                    cnt *= 10;
                if (cnt <= a)
                    len = x;
            }
            long sum = len * 45, cnt = 10;
            for (int i = 0; i < len - 1; i++) {
                sum *= 10;
                cnt *= 10;
            }
            a -= sum;
            long l = 0, r = cnt - 1;
            l += a % cnt;
            r += a % cnt;
            String add = get(a / cnt);
            if (a / cnt == 0 && l == 0)
                l++;
            out.print(add);
            if (a % cnt > 0 && a / cnt != 0)
                out.print(0);
            out.print(l + " ");
            out.print(add);
            out.println(r);
        }

    }

    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 print(Object... objects) {
            for (int i = 0; i < objects.length; i++) {
                if (i != 0) {
                    writer.print(' ');
                }
                writer.print(objects[i]);
            }
        }

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

        public void print(char i) {
            writer.print(i);
        }

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

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

        public void print(int i) {
            writer.print(i);
        }

    }

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

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

        public int read() {
            if (numChars == -1) {
                throw new InputMismatchException();
            }
            if (curChar >= numChars) {
                curChar = 0;
                try {
                    numChars = stream.read(buf);
                } catch (IOException e) {
                    throw new InputMismatchException();
                }
                if (numChars <= 0) {
                    return -1;
                }
            }
            return buf[curChar++];
        }

        public long nextLong() {
            int c = read();
            while (isSpaceChar(c)) {
                c = read();
            }
            int sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = read();
            }
            long res = 0;
            do {
                if (c < '0' || c > '9') {
                    throw new InputMismatchException();
                }
                res *= 10;
                res += c - '0';
                c = read();
            } while (!isSpaceChar(c));
            return res * sgn;
        }

        public boolean isSpaceChar(int c) {
            if (filter != null) {
                return filter.isSpaceChar(c);
            }
            return isWhitespace(c);
        }

        public static boolean isWhitespace(int c) {
            return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
        }

        public interface SpaceCharFilter {
            public boolean isSpaceChar(int ch);

        }

    }
}


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.io.Writer;
import java.io.OutputStreamWriter;
import java.util.InputMismatchException;
import java.io.IOException;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 *
 * @author step_by_step
 */
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);
        TaskC solver = new TaskC();
        solver.solve(1, in, out);
        out.close();
    }

    static class TaskC {
        public void solve(int testNumber, InputReader in, OutputWriter out) {
            long a = in.nextLong();
            if (a < 45) {
                for (int i = 0; i < a; i++)
                    out.print(1);
                out.print(' ');
                for (int i = 0; i < a; i++)
                    out.print(1);
                out.println();
                return;
            }
            long len = 0;
            for (long x = 2; x <= 17; x++) {
                long cnt = x * 45;
                for (int i = 0; i < x - 1; i++)
                    cnt *= 10;
                if (cnt > a) {
                    len = x - 1;
                    break;
                }
            }
            long sum = len * 45, cnt = 10;
            for (int i = 0; i < len - 1; i++) {
                sum *= 10;
                cnt *= 10;
            }
            a -= sum;
            long l = 0, r = cnt - 1;
            l += a % cnt;
            r += a % cnt;
            if (a / cnt == 0 && l == 0)
                l++;
            for (int i = 0; i < a / cnt; i++)
                out.print(1);
            if (a / cnt != 0)
                out.print(0);
            out.print(l + " ");
            for (int i = 0; i < a / cnt; i++)
                out.print(1);
            out.println(r);
            if (a / cnt + len > 199)
                while (true) {
                }
        }

    }

    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 print(Object... objects) {
            for (int i = 0; i < objects.length; i++) {
                if (i != 0) {
                    writer.print(' ');
                }
                writer.print(objects[i]);
            }
        }

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

        public void print(char i) {
            writer.print(i);
        }

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

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

        public void print(int i) {
            writer.print(i);
        }

    }

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

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

        public int read() {
            if (numChars == -1) {
                throw new InputMismatchException();
            }
            if (curChar >= numChars) {
                curChar = 0;
                try {
                    numChars = stream.read(buf);
                } catch (IOException e) {
                    throw new InputMismatchException();
                }
                if (numChars <= 0) {
                    return -1;
                }
            }
            return buf[curChar++];
        }

        public long nextLong() {
            int c = read();
            while (isSpaceChar(c)) {
                c = read();
            }
            int sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = read();
            }
            long res = 0;
            do {
                if (c < '0' || c > '9') {
                    throw new InputMismatchException();
                }
                res *= 10;
                res += c - '0';
                c = read();
            } while (!isSpaceChar(c));
            return res * sgn;
        }

        public boolean isSpaceChar(int c) {
            if (filter != null) {
                return filter.isSpaceChar(c);
            }
            return isWhitespace(c);
        }

        public static boolean isWhitespace(int c) {
            return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
        }

        public interface SpaceCharFilter {
            public boolean isSpaceChar(int ch);

        }

    }
}


import java.io.*;
import java.math.BigInteger;
import java.util.*;

public class E {

	static class Point {
		int x, y, id;

		public Point(int x, int y, int id) {
			this.x = x;
			this.y = y;
			this.id = id;
		}
	}

	static Comparator<Point> byAngle = new Comparator<E.Point>() {

		@Override
		public int compare(Point o1, Point o2) {
			return Long.compare((long) o1.x * o2.y, (long) o2.x * o1.y);
		}
	};

	void submit() {
		int r = nextInt();
		int q = nextInt();

		int[][] qs = new int[q][3];
		int n = 0;

		int ansSz = 0;

		for (int i = 0; i < q; i++) {

			qs[i][0] = nextInt();
			if (qs[i][0] == 1) {
				n++;
				qs[i][1] = nextInt();
				qs[i][2] = nextInt();
			} else if (qs[i][0] == 2) {
				qs[i][1] = nextInt() - 1;
			} else if (qs[i][0] == 3) {
				ansSz++;
				qs[i][1] = nextInt() - 1;
				qs[i][2] = nextInt() - 1;
			}
		}

		int[] xs, ys;

		Point[] px, py;

		{
			Point[] a = new Point[n];
			int ptr = 0;
			for (int i = 0; i < q; i++) {
				if (qs[i][0] == 1) {
					a[ptr] = new Point(qs[i][1] - r, qs[i][2], ptr);
					ptr++;
				}
			}

			px = makeUnique(a, byAngle);
			xs = new int[n];

			for (Point p : a) {
				xs[p.id] = Arrays.binarySearch(px, p, byAngle);
			}
		}

		{
			Point[] a = new Point[n];
			int ptr = 0;
			for (int i = 0; i < q; i++) {
				if (qs[i][0] == 1) {
					a[ptr] = new Point(qs[i][1] + r, qs[i][2], ptr);
					ptr++;
				}
			}

			py = makeUnique(a, byAngle.reversed());
			ys = new int[n];

			for (Point p : a) {
				ys[p.id] = Arrays.binarySearch(py, p, byAngle.reversed());
			}
		}

		int ptr = 0;

		ans = new boolean[ansSz];

		ansId = new ArrayList<>();

		int qryPtr = 0;

		for (int i = 0; i < q; i++) {

			if (qs[i][0] == 1) {
				addModify(xs[ptr], ys[ptr], 1);
				ptr++;
			} else if (qs[i][0] == 2) {
				int id = qs[i][1];
				addModify(xs[id], ys[id], -1);
			} else if (qs[i][0] == 3) {

				int p1 = qs[i][1];
				int p2 = qs[i][2];

				Point vx = px[Math.max(xs[p1], xs[p2])];
				Point vy = py[Math.max(ys[p1], ys[p2])];

				if (isInside(r, vx, vy)) {
				} else {
					ansId.add(qryPtr);
					addQuery(Math.max(xs[p1], xs[p2]), Math.max(ys[p1], ys[p2]));
				}

				qryPtr++;
			}
		}

		treeSize = px.length;
		goSmart();
	}

	boolean[] ans;
	ArrayList<Integer> ansId;

	int treeSize;

	static class Node {
		int l, r;
		Node left, right;

		ArrayList<Integer> allY = new ArrayList<>();
		int[] uniqueY;
		int[] fen;

		public Node(int l, int r) {
			this.l = l;
			this.r = r;

			if (r - l > 1) {
				int m = (l + r) >> 1;
				left = new Node(l, m);
				right = new Node(m, r);
			}
		}

		void mark(int x, int y) {
			if (r <= x) {
				allY.add(y);
				return;
			}
			if (l >= x) {
				return;
			}
			left.mark(x, y);
			right.mark(x, y);
		}

		void makeUnique() {
			makeUniqueHere();
			if (r - l > 1) {
				left.makeUnique();
				right.makeUnique();
			}
		}

		void add(int x, int y, int d) {
			int idx = Arrays.binarySearch(uniqueY, y);
			if (idx < 0) {
				idx = -idx - 1;
			}
			if (idx < fen.length) {
				addFen(fen, idx, d);
			}
			if (r - l > 1) {
				(x < left.r ? left : right).add(x, y, d);
			}
		}

		int getSum(int x, int y) {
			if (r <= x) {
				int idx = Arrays.binarySearch(uniqueY, y);
				return getFen(fen, idx);
			}
			if (l >= x) {
				return 0;
			}
			return left.getSum(x, y) + right.getSum(x, y);
		}

		void makeUniqueHere() {
			if (allY.isEmpty()) {
				uniqueY = new int[0];
				fen = new int[0];
			} else {
				Collections.sort(allY);
				int sz = 1;
				for (int i = 1; i < allY.size(); i++) {
					if (!allY.get(i).equals(allY.get(sz - 1))) {
						allY.set(sz, allY.get(i));
						sz++;
					}
				}

				uniqueY = new int[sz];
				fen = new int[sz];
				for (int i = 0; i < sz; i++) {
					uniqueY[i] = allY.get(i);
				}
			}
			allY = null;
		}
	}

	static void addFen(int[] fen, int idx, int delta) {
		for (int i = idx; i < fen.length; i |= i + 1) {
			fen[i] += delta;
		}
	}

	static int getFen(int[] fen, int idx) {
		int ret = 0;
		for (int i = idx; i >= 0; i = (i & (i + 1)) - 1) {
			ret += fen[i];
		}
		return ret;
	}

	void goSmart() {
		Node root = new Node(0, treeSize);
		for (int i = 0; i < qPtr; i++) {
			int x = qx[i];
			int y = qy[i];
			int d = qd[i];

//			System.err.println(x + " " + y + " " + d);

			if (d == Integer.MAX_VALUE) {
				root.mark(x + 1, y);
			}
		}

		root.makeUnique();

		int curAns = 0;

		for (int i = 0; i < qPtr; i++) {
			int x = qx[i];
			int y = qy[i];
			int d = qd[i];
			if (d == Integer.MAX_VALUE) {
//				System.err.println(root.getSum(x, y));
				int val = root.getSum(x + 1, y);
				if (val < 2) {
					throw new AssertionError();
				}
				ans[ansId.get(curAns)] = val == 2;
				curAns++;
			} else {
				root.add(x, y, d);
			}
		}

		for (boolean b : ans) {
			out.println(b ? "YES" : "NO");
		}
	}

	boolean isInside(int r, Point vl, Point vr) {
		long x = (long) vl.y * vr.x + (long) vl.x * vr.y;
		long y = (long) vl.y * vr.y;
		long d = (long) vl.y * vr.x - (long) vl.x * vr.y;

		return BigInteger.valueOf(x).pow(2).add(BigInteger.valueOf(y).pow(2))
				.compareTo(BigInteger.valueOf(d).pow(2)) < 0;
	}

	static final int QUERIES = 500000;

	int[] qx = new int[QUERIES];
	int[] qy = new int[QUERIES];
	int[] qd = new int[QUERIES];
	int qPtr = 0;

	void addModify(int x, int y, int d) {
		qx[qPtr] = x;
		qy[qPtr] = y;
		qd[qPtr] = d;
		qPtr++;
	}

	void addQuery(int x, int y) {
		qx[qPtr] = x;
		qy[qPtr] = y;
		qd[qPtr] = Integer.MAX_VALUE;
		qPtr++;
	}

	Point[] makeUnique(Point[] a, Comparator<Point> cmp) {
		a = a.clone();
		Arrays.sort(a, cmp);

		int sz = 1;
		for (int i = 1; i < a.length; i++) {
			if (cmp.compare(a[i], a[sz - 1]) != 0) {
				a[sz++] = a[i];
			}
		}
		return a;
	}

	void preCalc() {

	}

	void stress() {

	}

	void test() {

	}

	E() throws IOException {
		br = new BufferedReader(new InputStreamReader(System.in));
		out = new PrintWriter(System.out);
		preCalc();
		submit();
		// stress();
		// test();
		out.close();
	}

	static final Random rng = new Random();

	static int rand(int l, int r) {
		return l + rng.nextInt(r - l + 1);
	}

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

	BufferedReader br;
	PrintWriter out;
	StringTokenizer st;

	String nextToken() {
		while (st == null || !st.hasMoreTokens()) {
			try {
				st = new StringTokenizer(br.readLine());
			} catch (IOException e) {
				throw new RuntimeException(e);
			}
		}
		return st.nextToken();
	}

	String nextString() {
		try {
			return br.readLine();
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	int nextInt() {
		return Integer.parseInt(nextToken());
	}

	long nextLong() {
		return Long.parseLong(nextToken());
	}

	double nextDouble() {
		return Double.parseDouble(nextToken());
	}
}