// Arup Guha
// 4/25/2017
// Solution to 2017 NAIPC Problem H: Maximum Color Clique

// I got the idea for the dominating color and looping through the
// list in order from least to greatest vertex from Alex Coleman,
// who worked on this together with Michael Kirsche.

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

public class maxcolorclique {

	final public static long MOD = 1000000007L;
	final public static int MAXCOLOR = 300;
	final public static int MAXV = 300;

	// Stores graph.
	public static int n;
	public static int[][] adj;

	// Stores the "dominating" vertices and the colors of the edges that go from them to the vertices "lower" than them.
	public static int[] vertices;
	public static int[] colors;

	// Look up tables for combinations and sum of combinations on a single row of Pascal's Triangle.
	public static long[][] combo;
	public static long[][] sumcombo;

	public static void main(String[] args) throws Exception {

		// Set up combo tables.
		fillcombo();

		// Read input.
		BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
		n = Integer.parseInt(stdin.readLine().trim());
		adj = new int[n][n];
		for (int i=0; i<n; i++) {
			StringTokenizer tok = new StringTokenizer(stdin.readLine());
			for (int j=0; j<n; j++)
				adj[i][j] = Integer.parseInt(tok.nextToken())-1;
		}

		// First we go through after figure out "dominating" vertices in order.
		vertices = new int[n];
		colors = new int[n];
		boolean[] used = new boolean[n];

		// Figure out what vertex and edge color goes in slot i.
		for (int i=0; i<n; i++) {

			// Try each unused vertex.
			for (int j=0; j<n; j++) {
				if (used[j]) continue;

				int colorOut = -1;
				boolean worked = true;

				// Try seeing if all edges from j to all unused vertices are the same color.
				for (int k=0; k<n; k++) {
					if (used[k] || k==j) continue;
					int curColor = adj[j][k];
					if (colorOut == -1) colorOut = curColor;
					else if (colorOut != curColor) {
						worked = false;
						break;
					}
				}

				// If so, this is who we put next.
				if (worked) {
					vertices[i] = j;
					used[j] = true;
					colors[i] = colorOut;
					break;
				}
			}
		}

		// Stores all color frequencies of dominating colors. (Last doesn't get stored.
		int[] freq = new int[MAXCOLOR];
		for (int i=0; i<n-1; i++)
			freq[colors[i]]++;

		// Just making sure I delete objects not indexes.
		Integer[] vals = new Integer[MAXCOLOR];
		for (int i=0; i<MAXCOLOR; i++) vals[i] = new Integer(i);

		// Stores non-zero indexes into freq, the list of valid dominating colors.
		ArrayList<Integer> pos = new ArrayList<Integer>();
		for (int i=0; i<MAXCOLOR; i++)
			if (freq[i] > 0)
				pos.add(vals[i]);

		long res = 0L;

		// low represents the "lowest" vertex is the subset.
		for (int low=n-1; low>=0; low--) {

			// Go only through positive color frequencies.
			for (int i=0; i<pos.size(); i++) {

				int newi = pos.get(i);

				// max+1 is clique size(max is color above) and color is newi.
				for (int max=1; max<=freq[newi]; max++) {

					long tmp = 1L;

					// j is going through everything but i, allowing upto max or max-1 colors for that color.
					for (int j=0; j<pos.size(); j++) {
						if (i == j) continue;
						int choose = j < i ? max : max-1;
						tmp = (tmp*sumcombo[freq[pos.get(j)]][choose])%MOD;
					}

					// Our clique size is 1+max, the max vertices above me and me. tmp is the number of selections of
					// the other vertices in our subset from the other colors. We must multiply this by the number of
					// ways to choose our max vertices from the freq[newi] vertices above me with this color.
					res = (res + ((1+max)*tmp%MOD)*combo[freq[newi]][max])%MOD;
				}
			}

			// Subset that only contains lowest vertex.
			res = (res+1)%MOD;

			// Must adjust color frequencies and pos list here to sub out the next vertex's color.
			if (low > 0) {
				freq[colors[low-1]]--;
				if (freq[colors[low-1]] == 0)
					pos.remove(vals[colors[low-1]]);
			}
		}

		// Ta da!
		System.out.println(res);
	}

	public static void fillcombo() {

		// Initialize diagonals of pascal's triangle.
		combo = new long[MAXV+1][MAXV+1];
		for (int i=0; i<=MAXV; i++) {
			combo[i][0] = 1L;
			combo[i][i] = 1L;
		}

		// Fill in the rest.
		for (int i=2; i<=MAXV; i++)
			for (int j=1; j<i; j++)
				combo[i][j] = (combo[i-1][j-1]+combo[i-1][j])%MOD;

		sumcombo = new long[MAXV+1][];
		for (int i=0; i<=MAXV; i++)
			sumcombo[i] = Arrays.copyOf(combo[i], MAXV+1);

		// Now, make cumulative freq, where combo[i][j] = C(i,0) + C(i,1) + C(i,2) + ... + C(i,j).
		for (int i=1; i<=MAXV; i++)
			for (int j=1; j<=MAXV; j++)
				sumcombo[i][j] = (sumcombo[i][j] + sumcombo[i][j-1])%MOD;
	}
}
