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

// you can compare with output.txt and expected out
public class RoundEdu132F {
	MyPrintWriter out;
	MyScanner in;

//	final static long FIXED_RANDOM;
//	static {
//		FIXED_RANDOM = System.currentTimeMillis();
//	}
	final static String IMPOSSIBLE = "IMPOSSIBLE";
	final static String POSSIBLE = "POSSIBLE";
	final static String YES = "YES";
	final static String NO = "NO";

    private void initIO(boolean isFileIO) {
        if (System.getProperty("ONLINE_JUDGE") == null && isFileIO) {
        	try{
	            in = new MyScanner(new FileInputStream("input.txt"));
	            out = new MyPrintWriter(new FileOutputStream("output.txt"));
        	}
        	catch(FileNotFoundException e){
        		e.printStackTrace();
        	}
        }
        else{
    		in = new MyScanner(System.in);
    	    out = new MyPrintWriter(new BufferedOutputStream(System.out));
        }
    }

	public static void main(String[] args){
//		Scanner in = new Scanner(new BufferedReader(new InputStreamReader(System.in)));

		RoundEdu132F sol = new RoundEdu132F();
		sol.run();
    }

	private void run() {
		boolean isDebug = false;
		boolean isFileIO = true;
		boolean hasMultipleTests = false;

		initIO(isFileIO);

		int t = hasMultipleTests? in.nextInt() : 1;

	    for (int i = 1; i <= t; ++i) {
	    	if(isDebug){
		    	out.printf("Test %d\n", i);
	    	}

	    	getInput();

	    	ans = solve();

	    	printOutput();
	    }

	    in.close();
	    out.close();
	}

	int n, k, f;
	void getInput() {
		n = in.nextInt();
		k = in.nextInt();
		f = in.nextInt();
	}

	void printOutput() {
		out.printlnAns(ans);
	}

	static final long MOD = 998244353;
	int ans;
	int solve(){
		long ans = 0;

		// for each binary string s,
		// consider binary strings t of length n, where s is a prefix of t
		// we can have <= c_s among t

		// it's a full binary tree
		// where each vertex contains # of records in its subtree
		// and all records are at depth n

		// from each leaf, go up again, update each vertex to min(val, val(child1) + val(child2))
		// then the val(root) must be exactly f
		// where root is null string

		// the problem in this counting is we would have to use inclusion-exclusion due to duplicate cases
		// so we choose vertices representing disjoint subtrees
		// whose union can represent the whole tree
		// and whose sum is exactly f

		// for vertices under the subtrees, we can freely choose val
		// so that sum of siblings in each subtree >= val of root of subtree
		// for vertices above the subtrees, we can freely choose val between sum and k

		// so another approach:
		// for each vertex v of depth h
		// find # of ways to make sum exactly x
		// case 1: val(v) = x
		// add up ways(l, y)*ways(r, z) where y+z >= x
		// case 2: val(v) >= x+1
		// add up ways(l, y)*ways(r, z) where y+z = x

		// 2 1 1
		// case 1: c_0 = 1, c_1 = 0
		// 00 01 10 11
		// 1  0  0/1 0/1
		// 0  1  0/1 0/1
		// 1  1  0/1 0/1
		// -> 12

		// case 2: c_0 = 0, c_1 = 1
		// -> 12

		// case 3: c_0 = 1, c_1 = 1
		// 1 0 0 0
		// 0 1 0 0
		// 1 1 0 0
		// 0 0 1 0
		// 0 0 0 1
		// 0 0 1 1
		// -> 6

		// subtree_0 = 1 -> 3
		// c_0 = 1 -> 1 0, 0 1, 1 1

		// subtree_0 = 0 -> 5
		// c_0 = 0 -> 0/1, 0/1 -> 4
		// c_0 = 1 -> 0, 0 -> 1
		// 3*5 + 3*5 = 30

		// subtree_l = 0 -> 1
		// subtree_l = 1 -> 1

		// long[] ways = new long[f+2];
		int len = 1;
		while (len < f+2 + f+2)
	        len <<= 1;
		long[] ways = new long[len];
		long[] suffix = new long[f+2];

		for(int i=0; i<=k && i<=f; i++)
			ways[i] = 1;
		ways[f+1] = Math.max(0, k-f);

		for(int i=0; i<n; i++) {
			// long[] mult = multiplyPolynomial(ways, ways);
			square(ways);
			{
				long val = 0;
				for(int j=ways.length-1; j>=f+1; j--)
					val += ways[j];
				val %= MOD;
				suffix[f+1] = val;
			}
			for(int j=f; j>=0; j--){
				long val = suffix[j+1] + ways[j];
				val = val>=MOD? val-MOD: val;
				suffix[j] = val;
			}
			if(i < n-1) {
				for(int j=0; j <= k && j<=f; j++) {
					long val = suffix[j]; // c_curr = j
					val += ways[j]*(k-j); // j+1 ~ k
					val %= MOD;
					ways[j] = val;
				}
				{
					long val = suffix[f+1]*Math.max(0, k-f);
					val %= MOD;
					ways[f+1] = val;
				}
				Arrays.fill(ways, f+2, ways.length, 0);
			}
			else {
				ans = ways[f];
			}
		}

		return (int)ans;
	}

	static long pow(int a, int k, long p) {
		long m = k;
		long ans = 1;

		// curr = k^(2^i)
		long curr = a;

		// k^(2x+1) = (k^x)^2 * k
		while(m > 0) {
			if( (m&1) == 1 ) {
				ans *= curr;
				ans %= p;
			}
			m >>= 1;
			curr *= curr;
			curr %= p;
		}
		return ans;
	}

	// computes a^(p-2)
	static long inverse(int a, long p) {
		return pow(a, (int)(p-2), p);
	}

	// static final long MOD = 998_244_353; // = 1 + 7*17*2^23
	// primitive root is 3, i.e., the order of 3 is MOD-1
	// we have to find the 1<<23-th root
	static final int ROOT = (int) pow(3, 7*17, MOD);
	static final int ROOT_INV = (int) pow(ROOT, (int)MOD - 2, MOD);
	static final int ORDER = 1 << 23;

	static void swap(long[] a, int i, int j) {
		long temp = a[i];
		a[i] = a[j];
		a[j] = temp;
	}
	static void fft(long[] a, boolean isInvertedFFT) {
	    int n = a.length;

	    for (int i = 1, j = 0; i < n; i++) {
	        int bit = n >> 1;
	        for (; (j & bit) > 0; bit >>= 1)
	            j ^= bit;
	        j ^= bit;

	        if (i < j) {
	        	swap(a, i, j);
	        }
	    }

	    for (int len = 2; len <= n; len <<= 1) {
	        long wlen = isInvertedFFT ? ROOT_INV : ROOT;
	        for (int i = len; i < ORDER; i <<= 1)
	            wlen = wlen * wlen % MOD;

	        for (int i = 0; i < n; i += len) {
	        	long w = 1;
	            for (int j = 0; j < len / 2; j++) {
	                long u = a[i+j];
	                long v = a[i+j+len/2] * w % MOD;
	                a[i+j] =  u + v < MOD ? u + v : u + v - MOD;
	                a[i+j+len/2] = u - v >= 0 ? u - v : u - v + MOD;
	                w = w * wlen % MOD;
	            }
	        }
	    }

	    if (isInvertedFFT) {
	        int inv = (int) inverse(n, MOD);
	        for(int i=0; i<a.length; i++)
	        	a[i] = a[i]*inv%MOD;
	    }
	}

	static void square(long[] a) {
	    fft(a, false);
	    for (int i = 0; i < a.length; i++)
	        a[i] = a[i]*a[i] % MOD;
	    fft(a, true);
	}

	static long[] multiplyPolynomial(long[] a, long[] b) {
	    int n = 1;
	    while (n < a.length + b.length)
	        n <<= 1;
		long[] fa = Arrays.copyOf(a, n);
		long[] fb = Arrays.copyOf(b, n);

	    fft(fa, false);
	    fft(fb, false);
	    for (int i = 0; i < n; i++)
	        fa[i] = fa[i]*fb[i] % MOD;
	    fft(fa, true);

	    return fa;
	}

	public static class MyScanner {
		BufferedReader br;
		StringTokenizer st;

		// 32768?
		public MyScanner(InputStream is, int bufferSize) {
			br = new BufferedReader(new InputStreamReader(is), bufferSize);
		}

		public MyScanner(InputStream is) {
			br = new BufferedReader(new InputStreamReader(is));
			// br = new BufferedReader(new InputStreamReader(System.in));
			// br = new BufferedReader(new InputStreamReader(new FileInputStream("input.txt")));
		}

		public void close() {
			try {
				br.close();
			} catch (IOException e) {
				e.printStackTrace();
			}

		}

		String next() {
			while (st == null || !st.hasMoreElements()) {
				try {
					st = new StringTokenizer(br.readLine());
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			return st.nextToken();
		}

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

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

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

		String nextLine(){
			String str = "";
			try {
				str = br.readLine();
			} catch (IOException e) {
				e.printStackTrace();
			}
			return str;
		}

		int[][] nextTreeEdges(int n, int offset){
			int[][] e = new int[n-1][2];
			for(int i=0; i<n-1; i++){
				e[i][0] = nextInt()+offset;
				e[i][1] = nextInt()+offset;
			}
			return e;
		}

		int[][] nextMatrix(int n, int m) {
			return nextMatrix(n, m, 0);
		}

		int[][] nextMatrix(int n, int m, int offset) {
			int[][] mat = new int[n][m];
			for(int i=0; i<n; i++) {
				for(int j=0; j<m; j++) {
					mat[i][j] = nextInt()+offset;
				}
			}
			return mat;
		}

		int[][] nextPairs(int n){
			return nextPairs(n, 0);
		}

		int[][] nextPairs(int n, int offset) {
			int[][] xy = new int[2][n];
			for(int i=0; i<n; i++) {
				xy[0][i] = nextInt() + offset;
				xy[1][i] = nextInt() + offset;
			}
			return xy;
		}

		int[][] nextGraphEdges(){
			return nextGraphEdges(0);
		}

		int[][] nextGraphEdges(int offset) {
			int m = nextInt();
			int[][] e = new int[m][2];
			for(int i=0; i<m; i++){
				e[i][0] = nextInt()+offset;
				e[i][1] = nextInt()+offset;
			}
			return e;
		}

		int[] nextIntArray(int len) {
			return nextIntArray(len, 0);
		}
		int[] nextIntArray(int len, int offset){
	    	int[] a = new int[len];
			for(int j=0; j<len; j++)
	    		a[j] = nextInt()+offset;
	    	return a;
		}

		long[] nextLongArray(int len) {
			return nextLongArray(len, 0);
		}
		long[] nextLongArray(int len, int offset){
	    	long[] a = new long[len];
			for(int j=0; j<len; j++)
	    		a[j] = nextLong()+offset;
	    	return a;
		}
	}

	public static class MyPrintWriter extends PrintWriter{
		public MyPrintWriter(OutputStream os) {
			super(os);
		}

		public void printlnAns(long ans) {
			println(ans);
		}

		public void printlnAns(int ans) {
			println(ans);
		}

		public void printlnAns(boolean ans) {
			if(ans)
				println(YES);
			else
				println(NO);
		}

		public void printAns(long[] arr){
			if(arr != null && arr.length > 0){
				print(arr[0]);
				for(int i=1; i<arr.length; i++){
					print(" ");
					print(arr[i]);
				}
			}
		}
		public void printlnAns(long[] arr){
			printAns(arr);
			println();
		}

		public void printAns(int[] arr){
			if(arr != null && arr.length > 0){
				print(arr[0]);
				for(int i=1; i<arr.length; i++){
					print(" ");
					print(arr[i]);
				}
			}
		}
		public void printlnAns(int[] arr){
			printAns(arr);
			println();
		}

		public <T> void printAns(ArrayList<T> arr){
			if(arr != null && arr.size() > 0){
				print(arr.get(0));
				for(int i=1; i<arr.size(); i++){
					print(" ");
					print(arr.get(i));
				}
			}
		}
		public <T> void printlnAns(ArrayList<T> arr){
			printAns(arr);
			println();
		}

		public void printAns(int[] arr, int add){
			if(arr != null && arr.length > 0){
				print(arr[0]+add);
				for(int i=1; i<arr.length; i++){
					print(" ");
					print(arr[i]+add);
				}
			}
		}
		public void printlnAns(int[] arr, int add){
			printAns(arr, add);
			println();
		}

		public void printAns(ArrayList<Integer> arr, int add) {
			if(arr != null && arr.size() > 0){
				print(arr.get(0)+add);
				for(int i=1; i<arr.size(); i++){
					print(" ");
					print(arr.get(i)+add);
				}
			}
		}

		public void printlnAns(ArrayList<Integer> arr, int add){
			printAns(arr, add);
			println();
		}

		public void printlnAnsSplit(long[] arr, int split){
			if(arr != null){
				for(int i=0; i<arr.length; i+=split){
					print(arr[i]);
					for(int j=i+1; j<i+split; j++){
						print(" ");
						print(arr[j]);
					}
					println();
				}
			}
		}

		public void printlnAnsSplit(int[] arr, int split){
			if(arr != null){
				for(int i=0; i<arr.length; i+=split){
					print(arr[i]);
					for(int j=i+1; j<i+split; j++){
						print(" ");
						print(arr[j]);
					}
					println();
				}
			}
		}

		public <T> void printlnAnsSplit(ArrayList<T> arr, int split){
			if(arr != null && !arr.isEmpty()){
				for(int i=0; i<arr.size(); i+=split){
					print(arr.get(i));
					for(int j=i+1; j<i+split; j++){
						print(" ");
						print(arr.get(j));
					}
					println();
				}
			}
		}
	}

	static private void permutateAndSort(long[] a) {
		int n = a.length;
		Random R = new Random(System.currentTimeMillis());
		for(int i=0; i<n; i++) {
			int t = R.nextInt(n-i);
			long temp = a[n-1-i];
			a[n-1-i] = a[t];
			a[t] = temp;
		}
		Arrays.sort(a);
	}

	static private void permutateAndSort(int[] a) {
		int n = a.length;
		Random R = new Random(System.currentTimeMillis());
		for(int i=0; i<n; i++) {
			int t = R.nextInt(n-i);
			int temp = a[n-1-i];
			a[n-1-i] = a[t];
			a[t] = temp;
		}
		Arrays.sort(a);
	}

	static private int[][] constructChildren(int n, int[] parent, int parentRoot){
		int[][] childrens = new int[n][];

		int[] numChildren = new int[n];
		for(int i=0; i<parent.length; i++) {
			if(parent[i] != parentRoot)
				numChildren[parent[i]]++;
		}

		for(int i=0; i<n; i++) {
			childrens[i] = new int[numChildren[i]];
		}

		int[] idx = new int[n];
		for(int i=0; i<parent.length; i++) {
			if(parent[i] != parentRoot)
				childrens[parent[i]][idx[parent[i]]++] = i;
		}

		return childrens;
	}

	static private int[][][] constructDirectedNeighborhood(int n, int[][] e){
		int[] inDegree = new int[n];
		int[] outDegree = new int[n];
		for(int i=0; i<e.length; i++) {
			int u = e[i][0];
			int v = e[i][1];
			outDegree[u]++;
			inDegree[v]++;
		}

		int[][] inNeighbors = new int[n][];
		int[][] outNeighbors = new int[n][];
		for(int i=0; i<n; i++) {
			inNeighbors[i] = new int[inDegree[i]];
			outNeighbors[i] = new int[outDegree[i]];
		}

		int[] inIdx = new int[n];
		int[] outIdx = new int[n];
		for(int i=0; i<e.length; i++) {
			int u = e[i][0];
			int v = e[i][1];
			outNeighbors[u][outIdx[u]++] = v;
			inNeighbors[v][inIdx[v]++] = u;
		}

		return new int[][][] {inNeighbors, outNeighbors};
	}

	static private int[][] constructNeighborhood(int n, int[][] e) {
		int[] degree = new int[n];
		for(int i=0; i<e.length; i++) {
			int u = e[i][0];
			int v = e[i][1];
			degree[u]++;
			degree[v]++;
		}

		int[][] neighbors = new int[n][];
		for(int i=0; i<n; i++)
			neighbors[i] = new int[degree[i]];

		int[] idx = new int[n];
		for(int i=0; i<e.length; i++) {
			int u = e[i][0];
			int v = e[i][1];
			neighbors[u][idx[u]++] = v;
			neighbors[v][idx[v]++] = u;
		}

		return neighbors;
	}

	static private void drawGraph(int[][] e) {
		makeDotUndirected(e);
		try {
			final Process process = new ProcessBuilder("dot", "-Tpng", "graph.dot")
					.redirectOutput(new File("graph.png"))
					.start();
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}

	}

	static private void makeDotUndirected(int[][] e) {
		MyPrintWriter out2 = null;
		 try {
			out2 = new MyPrintWriter(new FileOutputStream("graph.dot"));
		} catch (FileNotFoundException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		out2.println("strict graph {");
		for(int i=0; i<e.length; i++){
			out2.println(e[i][0] + "--" + e[i][1] + ";");
		}
		out2.println("}");
		out2.close();
	}

	static private void makeDotDirected(int[][] e) {
		MyPrintWriter out2 = null;
		 try {
			out2 = new MyPrintWriter(new FileOutputStream("graph.dot"));
		} catch (FileNotFoundException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		out2.println("strict digraph {");
		for(int i=0; i<e.length; i++){
			out2.println(e[i][0] + "->" + e[i][1] + ";");
		}
		out2.println("}");
		out2.close();
	}

}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.Arrays;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.io.Closeable;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 */
public class Main {
    public static void main(String[] args) throws Exception {
        Thread thread = new Thread(null, new TaskAdapter(), "", 1 << 27);
        thread.start();
        thread.join();
    }

    static class TaskAdapter implements Runnable {
        @Override
        public void run() {
            InputStream inputStream = System.in;
            OutputStream outputStream = System.out;
            FastInput in = new FastInput(inputStream);
            FastOutput out = new FastOutput(outputStream);
            DShakeIt solver = new DShakeIt();
            solver.solve(1, in, out);
            out.close();
        }
    }

    static class DShakeIt {
        Modular mod = new Modular(1e9 + 7);
        int[][][][] h;
        int[][] g;
        int n;
        int flow;
        InverseNumber inv = new InverseNumber(100, mod);
        Debug debug = new Debug(false);

        public void solve(int testNumber, FastInput in, FastOutput out) {
            n = in.readInt();
            int m = in.readInt();
            flow = Math.max(n + 1, m);

            // f = new int[n + 1][flow + 1];
            h = new int[n + 1][flow + 1][n + 1][flow + 1];
            g = new int[n + 1][flow + 1];

            //SequenceUtils.deepFill(f, -1);
            SequenceUtils.deepFill(g, -1);
            SequenceUtils.deepFill(h, -1);

            //g(2, 0);

            int ans = f(n, m - 1);
            //ans = mod.mul(ans, fact.invFact(n));

            //debug.debug("f", f);
            debug.debug("g", g);
            debug.debug("h", h);
            out.println(ans);
        }

        public int h(int i, int j, int a, int b) {
            if (i < 0 || j < 0) {
                return 0;
            }
            if (h[i][j][a][b] == -1) {
                h[i][j][a][b] = 0;
                if (a == 0 || b == 0) {
                    return h[i][j][a][b] = i == 0 && j == 0 ? 1 : 0;
                }
                int limit = Math.min(i / a, j / b);
                int prod = 1;
                int aa = a;
                int bb = b;
                if (bb > 1) {
                    bb--;
                } else {
                    bb = flow;
                    aa--;
                }
                h[i][j][a][b] = h(i, j, aa, bb);
                for (int t = 1; t <= limit; t++) {
                    prod = mod.mul(prod, g(a - 1, b - 1) + t - 1);
                    prod = mod.mul(prod, inv.inverse(t));
                    int local = mod.mul(h(i - a * t, j - b * t, aa, bb),
                            prod);
                    h[i][j][a][b] = mod.plus(h[i][j][a][b], local);
                }

            }

            return h[i][j][a][b];
        }

        public int f(int i, int j) {
            return h(i, j, i, j);
        }

        public int g(int i, int j) {
            if (i < 0 || j < 0) {
                return 0;
            }
            if (g[i][j] == -1) {
                g[i][j] = 0;
                if (i == 0) {
                    return g[i][j] = j == 0 ? 1 : 0;
                }
                for (int a = 0; a <= i; a++) {
                    int c = i - a;
                    for (int b = j; b <= a + 1; b++) {
                        for (int d = j; d <= c + 1; d++) {
                            if (Math.min(b, d) != j) {
                                continue;
                            }
                            int way = mod.mul(f(a, b), f(c, d));

                            g[i][j] = mod.plus(g[i][j], way);
                        }
                    }
                }
            }

            return g[i][j];
        }

    }

    static class InverseNumber {
        int[] inv;

        public InverseNumber(int[] inv, int limit, Modular modular) {
            this.inv = inv;
            inv[1] = 1;
            int p = modular.getMod();
            for (int i = 2; i <= limit; i++) {
                int k = p / i;
                int r = p % i;
                inv[i] = modular.mul(-k, inv[r]);
            }
        }

        public InverseNumber(int limit, Modular modular) {
            this(new int[limit + 1], limit, modular);
        }

        public int inverse(int x) {
            return inv[x];
        }

    }

    static class FastOutput implements AutoCloseable, Closeable, Appendable {
        private StringBuilder cache = new StringBuilder(1 << 20);
        private final Writer os;

        public FastOutput append(CharSequence csq) {
            cache.append(csq);
            return this;
        }

        public FastOutput append(CharSequence csq, int start, int end) {
            cache.append(csq, start, end);
            return this;
        }

        public FastOutput(Writer os) {
            this.os = os;
        }

        public FastOutput(OutputStream os) {
            this(new OutputStreamWriter(os));
        }

        public FastOutput append(char c) {
            cache.append(c);
            return this;
        }

        public FastOutput append(int c) {
            cache.append(c);
            return this;
        }

        public FastOutput println(int c) {
            return append(c).println();
        }

        public FastOutput println() {
            cache.append(System.lineSeparator());
            return this;
        }

        public FastOutput flush() {
            try {
                os.append(cache);
                os.flush();
                cache.setLength(0);
            } catch (IOException e) {
                throw new UncheckedIOException(e);
            }
            return this;
        }

        public void close() {
            flush();
            try {
                os.close();
            } catch (IOException e) {
                throw new UncheckedIOException(e);
            }
        }

        public String toString() {
            return cache.toString();
        }

    }

    static class FastInput {
        private final InputStream is;
        private byte[] buf = new byte[1 << 13];
        private int bufLen;
        private int bufOffset;
        private int next;

        public FastInput(InputStream is) {
            this.is = is;
        }

        private int read() {
            while (bufLen == bufOffset) {
                bufOffset = 0;
                try {
                    bufLen = is.read(buf);
                } catch (IOException e) {
                    bufLen = -1;
                }
                if (bufLen == -1) {
                    return -1;
                }
            }
            return buf[bufOffset++];
        }

        public void skipBlank() {
            while (next >= 0 && next <= 32) {
                next = read();
            }
        }

        public int readInt() {
            int sign = 1;

            skipBlank();
            if (next == '+' || next == '-') {
                sign = next == '+' ? 1 : -1;
                next = read();
            }

            int val = 0;
            if (sign == 1) {
                while (next >= '0' && next <= '9') {
                    val = val * 10 + next - '0';
                    next = read();
                }
            } else {
                while (next >= '0' && next <= '9') {
                    val = val * 10 - next + '0';
                    next = read();
                }
            }

            return val;
        }

    }

    static class Modular {
        int m;

        public int getMod() {
            return m;
        }

        public Modular(int m) {
            this.m = m;
        }

        public Modular(long m) {
            this.m = (int) m;
            if (this.m != m) {
                throw new IllegalArgumentException();
            }
        }

        public Modular(double m) {
            this.m = (int) m;
            if (this.m != m) {
                throw new IllegalArgumentException();
            }
        }

        public int valueOf(int x) {
            x %= m;
            if (x < 0) {
                x += m;
            }
            return x;
        }

        public int valueOf(long x) {
            x %= m;
            if (x < 0) {
                x += m;
            }
            return (int) x;
        }

        public int mul(int x, int y) {
            return valueOf((long) x * y);
        }

        public int plus(int x, int y) {
            return valueOf(x + y);
        }

        public String toString() {
            return "mod " + m;
        }

    }

    static class Debug {
        private boolean offline;
        private PrintStream out = System.err;
        static int[] empty = new int[0];

        public Debug(boolean enable) {
            offline = enable && System.getSecurityManager() == null;
        }

        public Debug debug(String name, Object x) {
            return debug(name, x, empty);
        }

        public Debug debug(String name, Object x, int... indexes) {
            if (offline) {
                if (x == null || !x.getClass().isArray()) {
                    out.append(name);
                    for (int i : indexes) {
                        out.printf("[%d]", i);
                    }
                    out.append("=").append("" + x);
                    out.println();
                } else {
                    indexes = Arrays.copyOf(indexes, indexes.length + 1);
                    if (x instanceof byte[]) {
                        byte[] arr = (byte[]) x;
                        for (int i = 0; i < arr.length; i++) {
                            indexes[indexes.length - 1] = i;
                            debug(name, arr[i], indexes);
                        }
                    } else if (x instanceof short[]) {
                        short[] arr = (short[]) x;
                        for (int i = 0; i < arr.length; i++) {
                            indexes[indexes.length - 1] = i;
                            debug(name, arr[i], indexes);
                        }
                    } else if (x instanceof boolean[]) {
                        boolean[] arr = (boolean[]) x;
                        for (int i = 0; i < arr.length; i++) {
                            indexes[indexes.length - 1] = i;
                            debug(name, arr[i], indexes);
                        }
                    } else if (x instanceof char[]) {
                        char[] arr = (char[]) x;
                        for (int i = 0; i < arr.length; i++) {
                            indexes[indexes.length - 1] = i;
                            debug(name, arr[i], indexes);
                        }
                    } else if (x instanceof int[]) {
                        int[] arr = (int[]) x;
                        for (int i = 0; i < arr.length; i++) {
                            indexes[indexes.length - 1] = i;
                            debug(name, arr[i], indexes);
                        }
                    } else if (x instanceof float[]) {
                        float[] arr = (float[]) x;
                        for (int i = 0; i < arr.length; i++) {
                            indexes[indexes.length - 1] = i;
                            debug(name, arr[i], indexes);
                        }
                    } else if (x instanceof double[]) {
                        double[] arr = (double[]) x;
                        for (int i = 0; i < arr.length; i++) {
                            indexes[indexes.length - 1] = i;
                            debug(name, arr[i], indexes);
                        }
                    } else if (x instanceof long[]) {
                        long[] arr = (long[]) x;
                        for (int i = 0; i < arr.length; i++) {
                            indexes[indexes.length - 1] = i;
                            debug(name, arr[i], indexes);
                        }
                    } else {
                        Object[] arr = (Object[]) x;
                        for (int i = 0; i < arr.length; i++) {
                            indexes[indexes.length - 1] = i;
                            debug(name, arr[i], indexes);
                        }
                    }
                }
            }
            return this;
        }

    }

    static class SequenceUtils {
        public static void deepFill(Object array, int val) {
            if (!array.getClass().isArray()) {
                throw new IllegalArgumentException();
            }
            if (array instanceof int[]) {
                int[] intArray = (int[]) array;
                Arrays.fill(intArray, val);
            } else {
                Object[] objArray = (Object[]) array;
                for (Object obj : objArray) {
                    deepFill(obj, val);
                }
            }
        }

    }
}


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

public class D {

	static final int P = 1_000_000_007;

	static final int N = 52;

	void submit() {
		int n = nextInt();
		int m = nextInt();

		int[][] f = new int[N + 1][N + 1];

		f[0][1] = 1;

		for (int sz = 1; sz <= n; sz++) {

			int[][] dp = new int[sz + 1][N + 1];
			dp[0][1] = 1;

			int[][] cnt = new int[sz + 1][N + 1]; // [size][cut]

			for (int szL = 0; szL + 1 <= sz; szL++) {
				for (int cutL = 1; cutL <= N; cutL++) {
					for (int szR = 0; szL + szR + 1 <= sz; szR++) {
						for (int cutR = 1; cutR <= N; cutR++) {

							int szLR = szL + szR + 1;
							int cutLR = Math.min(cutL, cutR);

							cnt[szLR][cutLR] += (int) ((long) f[szL][cutL]
									* f[szR][cutR] % P);
							if (cnt[szLR][cutLR] >= P) {
								cnt[szLR][cutLR] -= P;
							}
						}
					}
				}
			}

			for (int addSz = 1; addSz <= sz; addSz++) {
				for (int addCut = 1; addCut <= N; addCut++) {

					if (cnt[addSz][addCut] == 0) {
						continue;
					}

					int[][] nextDp = new int[sz + 1][];
					for (int i = 0; i <= sz; i++) {
						nextDp[i] = dp[i].clone();
					}

					int smth = sz / addSz;

					int[] arrWays = new int[smth + 1];
					int base = cnt[addSz][addCut];

					arrWays[0] = 1;

					for (int i = 1; i <= smth; i++) {
						arrWays[i] = (int)((long)arrWays[i - 1] * inv[i] % P * base % P);
						base++;
						if (base == P) {
							base = 0;
						}
					}

					for (int cntAdd = 1; cntAdd <= smth; cntAdd++) {

						int ways = arrWays[cntAdd];

						for (int i = sz - addSz * cntAdd; i >= 0; i--) {
							for (int j = N - addCut * cntAdd; j >= 1; j--) {

								if (i + addSz * cntAdd <= sz
										&& j + addCut * cntAdd <= N) {

									nextDp[i + addSz * cntAdd][j + addCut * cntAdd] += (int) ((long) dp[i][j]
											* ways % P);
									if (nextDp[i + addSz * cntAdd][j + addCut
											* cntAdd] >= P) {
										nextDp[i + addSz * cntAdd][j + addCut
												* cntAdd] -= P;
									}

								}

							}
						}

					}

					dp = nextDp;

				}
			}

			for (int j = 1; j <= N; j++) {
				f[sz][j] = dp[sz][j];
			}

		}

//		for (int i = 0; i <= n; i++) {
//			for (int j = 1; j <= N; j++) {
//				if (f[i][j] != 0) {
//					System.err.println(i + " " + j + " -> " + f[i][j]);
//				}
//			}
//
//			System.err.println();
//		}

		out.println(f[n][m]);

	}

	int[] inv = new int[1000];
	{
		inv[0] = 0;
		inv[1] = 1;
		for (int i = 2; i < inv.length; i++) {
			inv[i] = P - (int) ((long) (P / i) * inv[P % i] % P);
		}
	}

	void preCalc() {

	}

	void stress() {

	}

	void test() {

	}

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

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


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

public class D {

	static final int P = 1_000_000_007;

	static final int N = 52;

	void submit() {
		int n = nextInt();
		int m = nextInt();

		int[][] f = new int[N + 1][N + 1];

		f[0][1] = 1;

		for (int sz = 1; sz <= n; sz++) {

			int[][] dp = new int[sz + 1][N + 1];
			dp[0][1] = 1;

			int[][] cnt = new int[sz + 1][N + 1]; // [size][cut]

			for (int szL = 0; szL + 1 <= sz; szL++) {
				for (int cutL = 1; cutL <= N; cutL++) {
					for (int szR = 0; szL + szR + 1 <= sz; szR++) {
						for (int cutR = 1; cutR <= N; cutR++) {

							int szLR = szL + szR + 1;
							int cutLR = Math.min(cutL, cutR);

							cnt[szLR][cutLR] += (int) ((long) f[szL][cutL]
									* f[szR][cutR] % P);
							if (cnt[szLR][cutLR] >= P) {
								cnt[szLR][cutLR] -= P;
							}
						}
					}
				}
			}

//			System.err.println("sz = " + sz);
//			for (int i = 0; i < cnt.length; i++) {
//				for (int j = 0; j < cnt[i].length; j++) {
//					if (cnt[i][j] != 0) {
//						System.err.println(i + " " + j + " --> " + cnt[i][j]);
//					}
//				}
//			}

			for (int addSz = 1; addSz <= sz; addSz++) {
				for (int addCut = 1; addCut <= N; addCut++) {

					int[][] nextDp = new int[sz + 1][];
					for (int i = 0; i <= sz; i++) {
						nextDp[i] = dp[i].clone();
					}

					for (int cntAdd = 1; cntAdd <= sz; cntAdd++) {

						int ways = getCoef(cnt[addSz][addCut], cntAdd);

						for (int i = sz; i >= 0; i--) {
							for (int j = N; j >= 1; j--) {

								if (i + addSz * cntAdd <= sz
										&& j + addCut * cntAdd <= N) {

									nextDp[i + addSz * cntAdd][j + addCut * cntAdd] += (int) ((long) dp[i][j]
											* ways % P);
									if (nextDp[i + addSz * cntAdd][j + addCut
											* cntAdd] >= P) {
										nextDp[i + addSz * cntAdd][j + addCut
												* cntAdd] -= P;
									}

								}

							}
						}

					}

					dp = nextDp;

				}
			}

			for (int j = 1; j <= N; j++) {
				f[sz][j] = dp[sz][j];
			}

		}
//
//		for (int i = 0; i <= n; i++) {
//			for (int j = 1; j <= N; j++) {
//				if (f[i][j] != 0) {
//					System.err.println(i + " " + j + " -> " + f[i][j]);
//				}
//			}
//
//			System.err.println();
//		}

		out.println(f[n][m]);

	}

	int[] inv = new int[1000];
	{
		inv[0] = 0;
		inv[1] = 1;
		for (int i = 2; i < inv.length; i++) {
			inv[i] = P - (int) ((long) (P / i) * inv[P % i] % P);
		}
	}

	int getCoef(int x, int y) {

		// y into x summands
		// C(x+y-1, y)
		int ret = 1;
		for (int i = 0; i < y; i++) {
			int lol = Math.floorMod(x + y - 1 - i, P);
			ret = (int)((long)ret * lol % P * inv[i + 1] % P);
		}

//		System.err.println(x + " " + y + " -> " + ret);

		return ret;
	}

	void preCalc() {

	}

	void stress() {

	}

	void test() {

	}

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

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


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

public class PQTree_test {

	BufferedReader br;
	PrintWriter out;
	StringTokenizer st;
	boolean eof;

	static PQNode[] collect(PQNode[] arr, int whatStatus) {
		int sz = 0;
		for (PQNode v : arr) {
			if (v.status == whatStatus) {
				sz++;
			}
		}

		PQNode[] ret = new PQNode[sz];
		int ptr = 0;
		for (PQNode v : arr) {
			if (v.status == whatStatus) {
				ret[ptr++] = v;
			}
		}

		return ret;
	}

	static PQNode makeNode(PQNode[] arr, int whatType) {
		if (arr.length == 0) {
			return null;
		}
		if (arr.length == 1) {
			return arr[0];
		}
		if (arr.length == 2) {
			whatType = PQNode.Q_NODE;
		}
		return new PQNode(whatType, arr);
	}

	static <T> void fullCopy(T[] src, T[] dest, int destPos) {
		System.arraycopy(src, 0, dest, destPos, src.length);
	}

	static PQNode[] appendFirst(PQNode v, PQNode[] arr) {
		if (v == null) {
			return arr;
		}
		PQNode[] ret = new PQNode[arr.length + 1];
		ret[0] = v;
		fullCopy(arr, ret, 1);
		return ret;
	}

	static PQNode[] appendLast(PQNode v, PQNode[] arr) {
		if (v == null) {
			return arr;
		}
		PQNode[] ret = new PQNode[arr.length + 1];
		fullCopy(arr, ret, 0);
		ret[arr.length] = v;
		return ret;
	}

	static PQNode[] concat(PQNode[] arr1, PQNode[] arr2) {
		PQNode[] ret = new PQNode[arr1.length + arr2.length];
		fullCopy(arr1, ret, 0);
		fullCopy(arr2, ret, arr1.length);
		return ret;
	}

	static <T> void reverse(T[] a) {
		for (int i = 0, j = a.length - 1; i < j; i++, j--) {
			T tmp = a[i];
			a[i] = a[j];
			a[j] = tmp;
		}
	}

	static class PQNode {
		static final int P_NODE = -1;
		static final int Q_NODE = -2;

		/**
		 * < 0 if P or Q node

		 * otherwise this node is leaf and type is number of element
		 */
		int type;
		PQNode[] child;

		public PQNode(int type, PQNode[] child) {
			this.type = type;
			this.child = child;
		}

		static final int EMPTY = 0;
		static final int FULL = 1;
		static final int PARTIAL = 2;
		static final int CONTAINS_ALL = 3;
		/**
		 * see above for possible values

		 * in case of partial, first children are in current query, then not
		 */
		int status;

		/**
		 * number of leafs from current query in this subtree
		 */
		int count;

		PQNode dfs(boolean[] b, int allQry) {

			if (type >= 0) {
				status = b[type] ? FULL : EMPTY;
				count = b[type] ? 1 : 0;
				return this;
			}

			count = 0;

			boolean allFull = true;
			boolean allEmpty = true;
			int cntPartial = 0;
			int[] idxPartial = new int[2];

			for (int i = 0; i < child.length; i++) {
				child[i] = child[i].dfs(b, allQry);
				if (child[i] == null) {
					return null;
				}
			}

			for (int i = 0; i < child.length; i++) {
				PQNode v = child[i];

				if (v.status == CONTAINS_ALL) {
					status = CONTAINS_ALL;
					return this;
				}
				allFull &= v.status == FULL;
				allEmpty &= v.status == EMPTY;
				if (v.status == PARTIAL) {
					if (cntPartial == 2) {
						return null;
					}
					idxPartial[cntPartial++] = i;
				}
				count += v.count;
			}

			boolean doesContainAll = count == allQry;

			if (allFull) {
				status = FULL;
				return this;
			}

			if (allEmpty) {
				status = EMPTY;
				return this;
			}

			if (cntPartial <= 1 && type == P_NODE && doesContainAll) {
				PQNode[] fulls = collect(child, FULL);
				PQNode[] emptys = collect(child, EMPTY);

				PQNode fullNode = makeNode(fulls, P_NODE);

				PQNode fullAndPartial;
				if (cntPartial == 0) {
					fullAndPartial = fullNode;
				} else {
					PQNode[] arr = appendFirst(fullNode,
							child[idxPartial[0]].child);
					fullAndPartial = makeNode(arr, Q_NODE);
				}

				PQNode[] arr = appendFirst(fullAndPartial, emptys);
				PQNode ret = makeNode(arr, P_NODE);
				ret.status = CONTAINS_ALL;
				return ret;
			}

			if (cntPartial <= 1 && type == P_NODE && !doesContainAll) {
				PQNode[] fulls = collect(child, FULL);
				PQNode[] emptys = collect(child, EMPTY);

				PQNode full = makeNode(fulls, P_NODE);
				if (full != null) {
					full.status = FULL;
				}
				PQNode empty = makeNode(emptys, P_NODE);
				if (empty != null) {
					empty.status = EMPTY;
				}

				PQNode ret;
				if (cntPartial == 1) {
					PQNode[] arr = appendFirst(full,
							appendLast(empty, child[idxPartial[0]].child));
					ret = makeNode(arr, Q_NODE);
				} else {
					ret = makeNode(new PQNode[] { full, empty }, Q_NODE);
				}
				ret.count = count;
				ret.status = PARTIAL;
				return ret;
			}

			if (cntPartial == 2 && type == P_NODE && doesContainAll) {
				PQNode[] fulls = collect(child, FULL);
				PQNode[] emptys = collect(child, EMPTY);

				PQNode fullNode = makeNode(fulls, P_NODE);

				reverse(child[idxPartial[0]].child);

				PQNode[] tmp = appendLast(fullNode, child[idxPartial[0]].child);
				PQNode fullAndPartial = makeNode(
						concat(tmp, child[idxPartial[1]].child), Q_NODE);

				PQNode[] arr = appendFirst(fullAndPartial, emptys);
				PQNode ret = makeNode(arr, P_NODE);
				ret.status = CONTAINS_ALL;
				return ret;
			}

			if (type == Q_NODE) {
				int size = child.length;
				for (int i = 0; i < cntPartial; i++) {
					size += child[idxPartial[i]].child.length - 1;
				}

				PQNode[] arr = new PQNode[size];
				int ptr = 0;

				boolean firstPartial = true;
				for (int i = 0; i< child.length; i++) {
					PQNode v = child[i];
					if (v.status == PARTIAL) {

						boolean shouldRev;
						if (cntPartial == 1) {
							if (i == 0) {
								shouldRev = child[i + 1].status == FULL;
							} else {
								shouldRev = child[i - 1].status == EMPTY;
							}
						} else {
							shouldRev = firstPartial;
							firstPartial = !firstPartial;
						}

						if (shouldRev) {
							reverse(v.child);
						}

						for (PQNode u : v.child) {
							arr[ptr++] = u;
						}
					} else {
						arr[ptr++] = v;
					}
				}

				if (arr[arr.length - 1].status == FULL) {
					reverse(arr);
				}

				ptr = arr.length - 1;
				while (ptr >= 0 && arr[ptr].status == EMPTY) {
					ptr--;
				}
				while (ptr >= 0 && arr[ptr].status == FULL) {
					ptr--;
				}

				if (ptr == -1) {
					PQNode ret = makeNode(arr, Q_NODE);
					ret.count = count;
					ret.status = doesContainAll ? CONTAINS_ALL : PARTIAL;
					return ret;
				}

				while (ptr >= 0 && arr[ptr].status == EMPTY) {
					ptr--;
				}

				if (ptr == -1 && doesContainAll) {
					PQNode ret = makeNode(arr, Q_NODE);
					ret.status = CONTAINS_ALL;
					return ret;
				}
			}

			return null;
		}

		void genRepr(StringBuilder sb) {
			if (type >= 0) {
				sb.append(type + " ");
				return;
			}
			sb.append(type == P_NODE ? "[" : "(");
			for (PQNode v : child) {
				v.genRepr(sb);
			}
			sb.append(type == P_NODE ? "]" : ")");
		}

		void getOrder(List<Integer> ret) {
			if (type >= 0) {
				ret.add(type);
				return;
			}
			for (PQNode v : child) {
				v.getOrder(ret);
			}
		}
	}

	static class PQTree {
		/**
		 * null if there are no permutations
		 */
		PQNode root;
		int n;

		public PQTree(int n) {
			this.n = n;
			PQNode[] arr = new PQNode[n];
			for (int i = 0; i < n; i++) {
				arr[i] = new PQNode(i, null);
			}
			root = makeNode(arr, PQNode.P_NODE);
		}

		void update(boolean[] b) {
			if (root == null) {
				return;
			}
			int cnt = 0;
			for (boolean flag : b) {
				cnt += flag ? 1 : 0;
			}
			if (cnt <= 1 || cnt == b.length) {
//				System.err.println("skipped");
				return;
			}
			root = root.dfs(b, cnt);

//			System.err.println(this);
		}

		@Override
		public String toString() {
			if (root == null) {
				return "null";
			}
			StringBuilder sb = new StringBuilder();
			root.genRepr(sb);
			return sb.toString();
		}

		List<Integer> getOrder() {
			List<Integer> ret = new ArrayList<>(n);
			root.getOrder(ret);
			return ret;
		}
	}

	void submit() throws IOException {
//		PQTree tree = new PQTree(6);
//		tree.update(new boolean[] { true, false, false, false, true, false });
//		tree.update(new boolean[] { true, true, false, true, true, false });
//		tree.update(new boolean[] { false, true, true, false, false, true});
//		tree.update(new boolean[] { false, true, false, false, true, false});
//		tree.update(new boolean[] { false, false, false, true, false, false});
//		tree.update(new boolean[] { false, true, true, false, false, true});

		int n = nextInt();
		PQTree tree = new PQTree(n);
		char[][] f = new char[n][];
		for (int i = 0; i < n; i++) {
			f[i] = nextToken().toCharArray();
			boolean[] b = new boolean[n];
			for (int j = 0; j < n; j++) {
				b[j] = f[i][j] == '1';
			}
			tree.update(b);
		}

		if (tree.root == null) {
			out.println("NO");
			return;
		}

		out.println("YES");
		List<Integer> order = tree.getOrder();
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < n; j++) {
				out.print(f[i][order.get(j)]);
			}
			out.println();
		}

	}

	static final Random rng = new Random();

	int[] genRandomPerm(int n) {
		int[] p = new int[n];
		for (int i = 0; i < n; i++) {
			int j = rng.nextInt(i + 1);
			p[i] = p[j];
			p[j] = i;
		}
		return p;
	}

	void oneTest(int n) {
		int[] p = genRandomPerm(n);
		char[][] f = new char[n][n];

		PQTree t = new PQTree(n);

		for (int i = 0; i < n; i++) {
			Arrays.fill(f[i], '0');
			int low = rng.nextInt(n);
			int high = rng.nextInt(n);
			if (low > high) {
				int tmp = low;
				low = high;
				high = tmp;
			}

			boolean[] b = new boolean[n];
			for (int j = low; j <= high; j++) {
				f[i][p[j]] = '1';
				b[p[j]] = true;
			}

			t.update(b);
		}

		if (t.root == null) {
			System.err.println(n);
			System.err.println(Arrays.toString(p));
			for (int i = 0; i < n; i++) {
				System.err.println(f[i]);
			}
			throw new AssertionError();
		}
	}

	void stress(int n) {
		for (int tst = 0; tst >= 0; tst++) {
			oneTest(n);
			System.err.println(tst);
		}
	}

	void test() {
		PQTree t = new PQTree(5);
		t.update(new boolean[]{false, false, true, true, false});
		t.update(new boolean[]{true, true, true, true, false});
		t.update(new boolean[]{true, true, true, false, true});
	}

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

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

	String nextToken() {
		while (st == null || !st.hasMoreTokens()) {
			try {
				st = new StringTokenizer(br.readLine());
			} catch (Exception e) {
				eof = true;
				return null;
			}
		}
		return st.nextToken();
	}

	String nextString() {
		try {
			return br.readLine();
		} catch (IOException e) {
			eof = true;
			return null;
		}
	}

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

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

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


//package round150;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.InputMismatchException;
import java.util.List;
import java.util.Set;

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

	void solve()
	{
		int n = ni();
		char[][] map = nm(n,n);

		Node root = universal(n);
		for(int i = 0;i < n;i++){
			Set<Integer> set = new HashSet<>();
			for(int j = 0;j < n;j++){
				if(map[i][j] == '1'){
					set.add(j);
				}
			}
			root = reduce(root, set);
		}
		if(root == null){
			out.println("NO");
		}else{
			out.println("YES");
			List<Integer> f = root.frontier();
			for(int i = 0;i < n;i++){
				for(int j = 0;j < n;j++){
					out.print(map[i][f.get(j)]);
				}
				out.println();
			}
		}
	}

	public static enum NodeType
	{
		LEAF, P, Q;
	}

	public static class Node
	{
		public NodeType type; // 0=leaf, 1=P, 2=Q
		public int id;
		public List<Node> children;

		public Node(int id) {
			this.type = NodeType.LEAF;
			this.id = id;
		}

		public Node(NodeType type, List<Node> children) {
			this.type = type;
			this.children = children;
		}

		public Node reverse()
		{
			for(int i = 0, j = children.size()-1;i < j;i++,j--){
				Node L = children.get(i);
				Node R = children.get(j);
				children.set(j, L);
				children.set(i, R);
			}
			return this;
		}

		public List<Integer> frontier()
		{
			List<Integer> ret = new ArrayList<Integer>();
			return frontierdfs(ret);
		}

		private List<Integer> frontierdfs(List<Integer> f)
		{
			if(this.type == NodeType.LEAF){
				f.add(this.id);
				return f;
			}else{
				for(Node c : this.children)c.frontierdfs(f);
				return f;
			}
		}

		@Override
		public String toString() {
			if(type == NodeType.LEAF){
				return "" + id;
			}else if(type == NodeType.P){
				StringBuilder sb = new StringBuilder("(");
				assert this.children.size() >= 1;
				for(Node c : this.children){
					sb.append(c.toString());
					sb.append(",");
				}
				sb.deleteCharAt(sb.length()-1);
				sb.append(")");
				return sb.toString();
			}else{
				StringBuilder sb = new StringBuilder("[");
				assert this.children.size() >= 1;
				for(Node c : this.children){
					sb.append(c.toString());
					sb.append(",");
				}
				sb.deleteCharAt(sb.length()-1);
				sb.append("]");
				return sb.toString();
			}
		}
	}

	public static Node universal(int n)
	{
		Node root = new Node(NodeType.P, new ArrayList<Node>());
		for(int i = 0;i < n;i++)root.children.add(new Node(i));
		return root;
	}

	public static Node reduce(Node root, Set<Integer> S)
	{
		if(root == null)return null;
		try{
			DFSResult res = dfs(root, S);
			return res.node;
		}catch(NoMatchError e){
			return null;
		}
	}

	@SuppressWarnings("serial")
	private static class NoMatchError extends Error{};

	private static class DFSResult
	{
		Node node;
		int nins;
		int des;
		boolean nomore;

		public DFSResult(Node node, int nins, int des, boolean nomore) {
			this.node = node;
			this.nins = nins;
			this.des = des;
			this.nomore = nomore;
		}
	}

	public static DFSResult dfs(Node root, Set<Integer> S)
	{
		if(root.type == NodeType.LEAF){
			int ins = S.contains(root.id) ? 1 : 0;
			return new DFSResult(root, ins, 1, ins == S.size());
		}else if(root.type == NodeType.P){
			List<Node> fulls = new ArrayList<>();
			List<Node> empties = new ArrayList<>();
			List<Node> partials = new ArrayList<>();
			int nins = 0;
			int des = 0;
			for(int i = 0;i < root.children.size();i++){
				DFSResult res = dfs(root.children.get(i), S);
				root.children.set(i, res.node);
				if(res.nomore)return new DFSResult(root, -1, -1, true);
				nins += res.nins;
				des += res.des;
				if(res.nins == res.des){
					fulls.add(res.node);
				}else if(res.nins == 0){
					empties.add(res.node);
				}else{
					partials.add(res.node);
					if(partials.size() > 2)throw new NoMatchError();
				}
			}
			if(fulls.size() == root.children.size()){
				return new DFSResult(root, nins, des, nins == S.size());
			}
			if(empties.size() == root.children.size()){
				return new DFSResult(root, 0, des, nins == S.size());
			}
			if(nins == S.size()){
				// root = ROOT(T,S)
				if(partials.isEmpty()){
					if(fulls.size() > 1){
						root.children = empties;
						Node f = new Node(NodeType.P, fulls);
						root.children.add(f);
					}
				}else if(partials.size() == 1){
					assert partials.get(0).type == NodeType.Q;
					if(fulls.size() >= 1){
						root.children = empties;
						root.children.addAll(partials);
						Node f = fulls.size() > 1 ? new Node(NodeType.P, fulls) : fulls.get(0);
						partials.get(0).children.add(f); // E-F
						if(root.children.size() == 1){
							root = partials.get(0);
						}
					}
				}else if(partials.size() == 2){
					assert partials.get(0).type == NodeType.Q;
					assert partials.get(1).type == NodeType.Q;
					root.children = empties;
					root.children.add(partials.get(0));
					if(fulls.size() >= 1){
						Node f = fulls.size() > 1 ? new Node(NodeType.P, fulls) : fulls.get(0);
						partials.get(0).children.add(f); // E-F
					}
					partials.get(0).children.addAll(partials.get(1).reverse().children);
				}
			}else{
				if(partials.isEmpty()){
					Node L = empties.size() > 1 ? new Node(NodeType.P, empties) : empties.get(0);
					Node R = fulls.size() > 1 ? new Node(NodeType.P, fulls) : fulls.get(0);
					Node ret = new Node(NodeType.Q, new ArrayList<Node>());
					ret.children.add(L);
					ret.children.add(R);
					root = ret;
				}else if(partials.size() == 1){
					assert partials.get(0).type == NodeType.Q;
					Node ret = partials.get(0);
					if(empties.size() >= 1){
						Node e = empties.size() > 1 ? new Node(NodeType.P, empties) : empties.get(0);
						ret.children.add(0, e);
					}
					if(fulls.size() >= 1){
						Node f = fulls.size() > 1 ? new Node(NodeType.P, fulls) : fulls.get(0);
						ret.children.add(f);
					}
					root = ret;
				}else if(partials.size() == 2){
					throw new NoMatchError();
				}
			}

			return new DFSResult(root, nins, des, nins == S.size());
		}else if(root.type == NodeType.Q){
			List<Node> fulls = new ArrayList<>();
			List<Node> empties = new ArrayList<>();
			List<Node> partials = new ArrayList<>();
			int nins = 0;
			int des = 0;
			// EEPFFPEE
			DFSResult[] ress = new DFSResult[root.children.size()];
			int firstF = -1;
			int lastF = -1;
			int lastP = -1;
			for(int i = 0;i < root.children.size();i++){
				DFSResult res = dfs(root.children.get(i), S);
				root.children.set(i, res.node);
				if(res.nomore)return new DFSResult(root, -1, -1, true);
				nins += res.nins;
				des += res.des;
				ress[i] = res;

				if(res.nins == res.des){
					if(firstF == -1)firstF = i;
					lastF = i;
					fulls.add(res.node);
				}else if(res.nins == 0){
					empties.add(res.node);
				}else{
					lastP = i;
					partials.add(res.node);
					if(partials.size() > 2)throw new NoMatchError();
				}
			}

			// validation
			if(firstF != -1){
				// FFF
				if(lastF - firstF + 1 != fulls.size())throw new NoMatchError();
				int np = 0;
				if(firstF - 1 >= 0 && ress[firstF-1].nins > 0)np++;
				if(lastF + 1 < root.children.size() && ress[lastF + 1].nins > 0)np++;
				if(np != partials.size())throw new NoMatchError();
			}else if(lastP != -1){
				if(partials.size() == 2 && !(lastP - 1 >= 0 && ress[lastP - 1].nins > 0))throw new NoMatchError();
			}

			if(fulls.size() == root.children.size()){
				return new DFSResult(root, nins, des, nins == S.size());
			}
			if(empties.size() == root.children.size()){
				return new DFSResult(root, 0, des, nins == S.size());
			}

			if(nins == S.size()){
				// root = ROOT(T,S)
				if(partials.isEmpty()){
					// as is
				}else if(partials.size() == 1){
					assert partials.get(0).type == NodeType.Q;
					if(fulls.size() >= 1){
						if(lastP == firstF - 1){
							root.children.remove(lastP);
							root.children.addAll(lastP, partials.get(0).children); // E-F
						}else{
							root.children.remove(lastP);
							root.children.addAll(lastP, partials.get(0).reverse().children); // F-E
						}
					}
				}else if(partials.size() == 2){
					assert partials.get(0).type == NodeType.Q;
					assert partials.get(1).type == NodeType.Q;
					int firstP = lastP - fulls.size() - 1;
					root.children.remove(lastP);
					root.children.addAll(lastP, partials.get(1).reverse().children); // F-E
					root.children.remove(firstP);
					root.children.addAll(firstP, partials.get(0).children); // E-F
				}
			}else{
				if(firstF == -1){
					// partial only
					if(partials.size() == 1){
						if(lastP == 0){
							root.reverse();
							int ind = root.children.size()-1;
							root.children.remove(ind);
							root.children.addAll(ind, partials.get(0).children); // E-F
						}else if(lastP == root.children.size()-1){
							int ind = root.children.size()-1;
							root.children.remove(ind);
							root.children.addAll(ind, partials.get(0).children); // E-F
						}else{
							throw new NoMatchError();
						}
					}else{
						throw new NoMatchError();
					}
				}else if(firstF == 0){
					root.reverse();
					if(partials.size() == 1){
						int ind = root.children.size() - 1 - lastP;
						root.children.remove(ind);
						root.children.addAll(ind, partials.get(0).children); // E-F
					}else if(partials.size() > 1){
						throw new NoMatchError();
					}
				}else if(lastF == root.children.size() - 1){
					if(partials.size() == 1){
						int ind = lastP;
						root.children.remove(ind);
						root.children.addAll(ind, partials.get(0).children); // E-F
					}else if(partials.size() > 1){
						throw new NoMatchError();
					}
				}else{
					throw new NoMatchError();
				}
			}
			return new DFSResult(root, nins, des, nins == S.size());
		}else{
			throw new NoMatchError();
		}
	}

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

	private byte[] inbuf = new byte[1024];
	public 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.*;
import java.util.*;

public class PQTree_test {

	BufferedReader br;
	PrintWriter out;
	StringTokenizer st;
	boolean eof;

	static PQNode[] collect(PQNode[] arr, int whatStatus) {
		int sz = 0;
		for (PQNode v : arr) {
			if (v.status == whatStatus) {
				sz++;
			}
		}

		PQNode[] ret = new PQNode[sz];
		int ptr = 0;
		for (PQNode v : arr) {
			if (v.status == whatStatus) {
				ret[ptr++] = v;
			}
		}

		return ret;
	}

	static PQNode makeNode(PQNode[] arr, int whatType) {
		if (arr.length == 0) {
			return null;
		}
		if (arr.length == 1) {
			return arr[0];
		}
		if (arr.length == 2) {
			whatType = PQNode.Q_NODE;
		}
		return new PQNode(whatType, arr);
	}

	static <T> void fullCopy(T[] src, T[] dest, int destPos) {
		System.arraycopy(src, 0, dest, destPos, src.length);
	}

	static PQNode[] appendFirst(PQNode v, PQNode[] arr) {
		if (v == null) {
			return arr;
		}
		PQNode[] ret = new PQNode[arr.length + 1];
		ret[0] = v;
		fullCopy(arr, ret, 1);
		return ret;
	}

	static PQNode[] appendLast(PQNode v, PQNode[] arr) {
		if (v == null) {
			return arr;
		}
		PQNode[] ret = new PQNode[arr.length + 1];
		fullCopy(arr, ret, 0);
		ret[arr.length] = v;
		return ret;
	}

	static PQNode[] concat(PQNode[] arr1, PQNode[] arr2) {
		PQNode[] ret = new PQNode[arr1.length + arr2.length];
		fullCopy(arr1, ret, 0);
		fullCopy(arr2, ret, arr1.length);
		return ret;
	}

	static <T> void reverse(T[] a) {
		for (int i = 0, j = a.length - 1; i < j; i++, j--) {
			T tmp = a[i];
			a[i] = a[j];
			a[j] = tmp;
		}
	}

	static class PQNode {
		static final int P_NODE = -1;
		static final int Q_NODE = -2;

		/**
		 * < 0 if P or Q node

		 * otherwise this node is leaf and type is number of element
		 */
		int type;
		PQNode[] child;

		public PQNode(int type, PQNode[] child) {
			this.type = type;
			this.child = child;
		}

		static final int EMPTY = 0;
		static final int FULL = 1;
		static final int PARTIAL = 2;
		static final int CONTAINS_ALL = 3;
		/**
		 * see above for possible values

		 * in case of partial, first children are in current query, then not
		 */
		int status;

		/**
		 * number of leafs from current query in this subtree
		 */
		int count;

		PQNode dfs(boolean[] b, int allQry) {

			if (type >= 0) {
				status = b[type] ? FULL : EMPTY;
				count = b[type] ? 1 : 0;
				return this;
			}

			count = 0;

			boolean allFull = true;
			boolean allEmpty = true;
			int cntPartial = 0;
			int[] idxPartial = new int[2];

			for (int i = 0; i < child.length; i++) {
				child[i] = child[i].dfs(b, allQry);
				if (child[i] == null) {
					return null;
				}
			}

			for (int i = 0; i < child.length; i++) {
				PQNode v = child[i];

				if (v.status == CONTAINS_ALL) {
					status = CONTAINS_ALL;
					return this;
				}
				allFull &= v.status == FULL;
				allEmpty &= v.status == EMPTY;
				if (v.status == PARTIAL) {
					if (cntPartial == 2) {
						return null;
					}
					idxPartial[cntPartial++] = i;
				}
				count += v.count;
			}

			boolean doesContainAll = count == allQry;

			if (allFull) {
				status = FULL;
				return this;
			}

			if (allEmpty) {
				status = EMPTY;
				return this;
			}

			if (cntPartial <= 1 && type == P_NODE && doesContainAll) {
				PQNode[] fulls = collect(child, FULL);
				PQNode[] emptys = collect(child, EMPTY);

				PQNode fullNode = makeNode(fulls, P_NODE);

				PQNode fullAndPartial;
				if (cntPartial == 0) {
					fullAndPartial = fullNode;
				} else {
					PQNode[] arr = appendFirst(fullNode,
							child[idxPartial[0]].child);
					fullAndPartial = makeNode(arr, Q_NODE);
				}

				PQNode[] arr = appendFirst(fullAndPartial, emptys);
				PQNode ret = makeNode(arr, P_NODE);
				ret.status = CONTAINS_ALL;
				return ret;
			}

			if (cntPartial <= 1 && type == P_NODE && !doesContainAll) {
				PQNode[] fulls = collect(child, FULL);
				PQNode[] emptys = collect(child, EMPTY);

				PQNode full = makeNode(fulls, P_NODE);
				PQNode empty = makeNode(emptys, P_NODE);

				PQNode ret;
				if (cntPartial == 1) {
					PQNode[] arr = appendFirst(full,
							appendLast(empty, child[idxPartial[0]].child));
					ret = makeNode(arr, Q_NODE);
				} else {
					ret = makeNode(new PQNode[] { full, empty }, Q_NODE);
				}
				ret.count = count;
				ret.status = PARTIAL;
				return ret;
			}

			if (cntPartial == 2 && type == P_NODE && doesContainAll) {
				PQNode[] fulls = collect(child, FULL);
				PQNode[] emptys = collect(child, EMPTY);

				PQNode fullNode = makeNode(fulls, P_NODE);

				reverse(child[idxPartial[0]].child);

				PQNode[] tmp = appendLast(fullNode, child[idxPartial[0]].child);
				PQNode fullAndPartial = makeNode(
						concat(tmp, child[idxPartial[1]].child), Q_NODE);

				PQNode[] arr = appendFirst(fullAndPartial, emptys);
				PQNode ret = makeNode(arr, P_NODE);
				ret.status = CONTAINS_ALL;
				return ret;
			}

			if (type == Q_NODE) {
				int size = child.length;
				for (int i = 0; i < cntPartial; i++) {
					size += child[idxPartial[i]].child.length - 1;
				}

				PQNode[] arr = new PQNode[size];
				int ptr = 0;

				boolean firstPartial = true;
				for (int i = 0; i< child.length; i++) {
					PQNode v = child[i];
					if (v.status == PARTIAL) {

						boolean shouldRev;
						if (cntPartial == 1) {
							if (i == 0) {
								shouldRev = child[i + 1].status == FULL;
							} else {
								shouldRev = child[i - 1].status == EMPTY;
							}
						} else {
							shouldRev = firstPartial;
							firstPartial = !firstPartial;
						}

						if (shouldRev) {
							reverse(v.child);
						}

						for (PQNode u : v.child) {
							arr[ptr++] = u;
						}
					} else {
						arr[ptr++] = v;
					}
				}

				if (arr[arr.length - 1].status == FULL) {
					reverse(arr);
				}

				ptr = arr.length - 1;
				while (ptr >= 0 && arr[ptr].status == EMPTY) {
					ptr--;
				}
				while (ptr >= 0 && arr[ptr].status == FULL) {
					ptr--;
				}

				if (ptr == -1) {
					PQNode ret = makeNode(arr, Q_NODE);
					ret.count = count;
					ret.status = doesContainAll ? CONTAINS_ALL : PARTIAL;
					return ret;
				}

				while (ptr >= 0 && arr[ptr].status == EMPTY) {
					ptr--;
				}

				if (ptr == -1 && doesContainAll) {
					PQNode ret = makeNode(arr, Q_NODE);
					ret.status = CONTAINS_ALL;
					return ret;
				}
			}

			return null;
		}

		void genRepr(StringBuilder sb) {
			if (type >= 0) {
				sb.append(type + " ");
				return;
			}
			sb.append(type == P_NODE ? "[" : "(");
			for (PQNode v : child) {
				v.genRepr(sb);
			}
			sb.append(type == P_NODE ? "]" : ")");
		}

		void getOrder(List<Integer> ret) {
			if (type >= 0) {
				ret.add(type);
				return;
			}
			for (PQNode v : child) {
				v.getOrder(ret);
			}
		}
	}

	static class PQTree {
		/**
		 * null if there are no permutations
		 */
		PQNode root;
		int n;

		public PQTree(int n) {
			this.n = n;
			PQNode[] arr = new PQNode[n];
			for (int i = 0; i < n; i++) {
				arr[i] = new PQNode(i, null);
			}
			root = makeNode(arr, PQNode.P_NODE);
		}

		void update(boolean[] b) {
			if (root == null) {
				return;
			}
			int cnt = 0;
			for (boolean flag : b) {
				cnt += flag ? 1 : 0;
			}
			if (cnt <= 1 || cnt == b.length) {
				return;
			}
			root = root.dfs(b, cnt);

//			System.err.println(this);

		}

		@Override
		public String toString() {
			if (root == null) {
				return "null";
			}
			StringBuilder sb = new StringBuilder();
			root.genRepr(sb);
			return sb.toString();
		}

		List<Integer> getOrder() {
			List<Integer> ret = new ArrayList<>(n);
			root.getOrder(ret);
			return ret;
		}
	}

	void solve() throws IOException {
//		PQTree tree = new PQTree(6);
//		tree.update(new boolean[] { true, false, false, false, true, false });
//		tree.update(new boolean[] { true, true, false, true, true, false });
//		tree.update(new boolean[] { false, true, true, false, false, true});
//		tree.update(new boolean[] { false, true, false, false, true, false});
//		tree.update(new boolean[] { false, false, false, true, false, false});
//		tree.update(new boolean[] { false, true, true, false, false, true});

		int n = nextInt();
		PQTree tree = new PQTree(n);
		char[][] f = new char[n][];
		for (int i = 0; i < n; i++) {
			f[i] = nextToken().toCharArray();
			boolean[] b = new boolean[n];
			for (int j = 0; j < n; j++) {
				b[j] = f[i][j] == '1';
			}
			tree.update(b);
		}

		if (tree.root == null) {
			out.println("NO");
			return;
		}

		out.println("YES");
		List<Integer> order = tree.getOrder();
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < n; j++) {
				out.print(f[i][order.get(j)]);
			}
			out.println();
		}

	}

	PQTree_test() throws IOException {
		br = new BufferedReader(new InputStreamReader(System.in));
		out = new PrintWriter(System.out);
		solve();
		out.close();
	}

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

	String nextToken() {
		while (st == null || !st.hasMoreTokens()) {
			try {
				st = new StringTokenizer(br.readLine());
			} catch (Exception e) {
				eof = true;
				return null;
			}
		}
		return st.nextToken();
	}

	String nextString() {
		try {
			return br.readLine();
		} catch (IOException e) {
			eof = true;
			return null;
		}
	}

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

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

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


import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.InputMismatchException;
import java.io.IOException;
import java.util.ArrayList;
import java.io.InputStream;

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

class TaskE {
    char[][] A;
    int[] ans;
    ArrayList<Integer>[] B;
    int[] inGroup;

    public void solve(int testNumber, InputReader in, PrintWriter out) {
        int N = in.nextInt();
        A = new char[N][];
        for (int i = 0; i < N; i++) {
            A[i] = in.nextString().toCharArray();
        }

        ArrayList<Integer> rows = new ArrayList<Integer>();
        ArrayList<Integer> cols = new ArrayList<Integer>();
        for (int i = 0; i < N; i++) {
            rows.add(i);
            cols.add(i);
        }
        ans = new int[N + 1];

        B = new ArrayList[N];
        for (int i = 0; i < N; i++) {
            B[i] = new ArrayList<Integer>();
            for (int j = 0; j < N; j++) {
                if (A[i][j] == '1') {
                    B[i].add(j);
                }
            }
        }

        inGroup = new int[N];
        if (go(rows, cols)) {
            out.println("YES");
            for (int i = 0; i < N; i++) {
                for (int j = 1; j <= N; j++) {
                    out.print(A[i][ans[j]]);
                }
                out.println();
            }
        }
        else {
            out.println("NO");
        }
    }

    private boolean go(ArrayList<Integer> rows, ArrayList<Integer> cols) {
        if (rows.isEmpty()) {
            for (int col : cols) {
                ans[++ans[0]] = col;
            }
            return true;
        }

        int pmax = 0;
        for (int i = 1; i < rows.size(); i++) {
            if (B[rows.get(i)].size() > B[rows.get(pmax)].size()) {
                pmax = i;
            }
        }
        rows.remove(pmax);

        ArrayList<ArrayList<Integer>> groups = new ArrayList<ArrayList<Integer>>();
        ArrayList<Integer> ones = new ArrayList<Integer>();
        ArrayList<Integer> zeros = new ArrayList<Integer>();
        split(pmax, cols, ones, zeros);
        groups.add(ones);
        groups.add(zeros);

        if (rows.isEmpty()) {
            for (ArrayList<Integer> gcols : groups) {
                for (int gcol : gcols) {
                    ans[++ans[0]] = gcol;
                }
            }
            return true;
        }
        if (ones.isEmpty() || zeros.isEmpty()) {
            return go(rows, cols);
        }

        int p = -1;
        int special = groups.get(groups.size() - 1).size();
        while ((p = find(groups, rows)) != -1) {
            rows.remove((Integer) p);

            int state = 0;
            boolean maybe = false;
            ArrayList<ArrayList<Integer>> ngroups = new ArrayList<ArrayList<Integer>>();
            for (int i = 0; i < groups.size(); i++) {
                ArrayList<Integer> group = groups.get(i);
                ones = new ArrayList<Integer>();
                zeros = new ArrayList<Integer>();
                split(p, group, ones, zeros);

                if (state == 0) {
                    if (!zeros.isEmpty()) ngroups.add(zeros);
                    if (!ones.isEmpty()) {
                        ngroups.add(ones);
                        state = 1;
                    }
                }
                else if (state == 1) {
                    if (!ones.isEmpty()) ngroups.add(ones);
                    if (!zeros.isEmpty()) {
                        ngroups.add(zeros);
                        state = 2;
                    }
                }
                else if (state == 2) {
                    if (!zeros.isEmpty()) ngroups.add(zeros);
                    if (!ones.isEmpty()) {
                        if (i + 1 < groups.size() || special == 0) {
                            return false;
                        }
                        else {
                            maybe = true;
                        }
                    }
                }
                if (i == groups.size() - 1) {
                    special -= ones.size();
                }
            }

            if (maybe) {
                ngroups = new ArrayList<ArrayList<Integer>>();
                state = 0;
                for (int i = 0; i < groups.size(); i++) {
                    ArrayList<Integer> group = groups.get(i);
                    ones = new ArrayList<Integer>();
                    zeros = new ArrayList<Integer>();
                    split(p, group, ones, zeros);

                    if (i == groups.size() - 1) {
                        if (!ones.isEmpty()) ngroups.add(0, ones);
                        if (!zeros.isEmpty()) ngroups.add(zeros);
                        continue;
                    }
                    if (!ones.isEmpty()) {
                        if (state == 1) return false;
                        ngroups.add(ones);
                    }
                    if (!zeros.isEmpty()) {
                        if (state == 0) state = 1;
                        ngroups.add(zeros);
                    }
                }
            }

            groups = ngroups;
        }

        ArrayList<Integer>[] groupRows = new ArrayList[groups.size()];
        for (int i = 0; i < groups.size(); i++) {
            groupRows[i] = new ArrayList<Integer>();
        }
        for (int r : rows) {
            int f = B[r].get(0);
            int g = inGroup[f];
            groupRows[g].add(r);
        }
        for (int i = 0; i < groups.size(); i++) {
            ArrayList<Integer> group = groups.get(i);
            if (!go(groupRows[i], group)) {
                return false;
            }
        }
        return true;
    }

    private int find(ArrayList<ArrayList<Integer>> groups, ArrayList<Integer> rows) {
        for (int i = 0; i < groups.size(); i++) {
            ArrayList<Integer> group = groups.get(i);
            for (int col : group) {
                inGroup[col] = i;
            }
        }
        for (int r : rows) {
            for (int j = 1; j < B[r].size(); j++) {
                if (inGroup[ B[r].get(j - 1) ] != inGroup[ B[r].get(j) ]) {
                    return r;
                }
            }
        }
        return -1;
    }

    private void split(int row, ArrayList<Integer> cols, ArrayList<Integer> ones, ArrayList<Integer> zeros) {
        for (int col : cols) {
            if (A[row][col] == '1') {
                ones.add(col);
            }
            else {
                zeros.add(col);
            }
        }
    }
}

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 (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 int nextInt() {
        return Integer.parseInt(nextString());
    }

    public String nextString() {
        int c = read();
        while (isSpaceChar(c))
            c = read();
        StringBuffer res = new StringBuffer();
        do {
            res.appendCodePoint(c);
            c = read();
        } while (!isSpaceChar(c));

        return res.toString();
    }

    private boolean isSpaceChar(int c) {
        return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
    }

}


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

public class E {

    BufferedReader br;
    PrintWriter out;
    StringTokenizer st;
    boolean eof;

    void solve() throws IOException {
        int n = nextInt();
        int m = nextInt();

        long[] a = new long[n];
        for (int i = 0; i < n; i++)
            a[i] = nextLong();

        long ans = 0;

        int maxP = m / n;
        for (int p = 1; p <= maxP; p++) {
            long minLastSum = (long)p * (p + 1) / 2 * n;
            if (a[n - 1] < minLastSum)
                continue;
            long maxLastSum = (long)m * p - (long)n * p * (p - 1) / 2;
            long[] money = new long[n];
            money[n - 1] = Math.min(maxLastSum, a[n - 1]);
            for (int i = n - 2; i >= 0; i--)
                money[i] = Math.min(a[i], money[i + 1] - p);

            long firstMax = (long)(m + 1) * p - (long)n * p * (p + 1) / 2;
            long diff = firstMax - money[0];
            if (diff < 0)
                throw new AssertionError();
            long firstPay = diff <= m - p * n ? (m - p * n + 1 - diff) : 1;
            long free = (m - firstPay + 1) - n * p;

            long cur = money[0];
            long last = money[0];
            for (int j = 1; j < n; j++) {
                long now = last + p;
                long shift = Math.min(free, money[j] - now);
                free -= shift;
                last = now + shift;
                cur += last;
            }

            ans = Math.max(ans, cur);
        }

        out.println(ans);
    }

    void inp() throws IOException {
        br = new BufferedReader(new InputStreamReader(System.in));
        out = new PrintWriter(System.out);
        solve();
        out.close();
    }

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

    String nextToken() {
        while (st == null || !st.hasMoreTokens()) {
            try {
                st = new StringTokenizer(br.readLine());
            } catch (Exception e) {
                eof = true;
                return null;
            }
        }
        return st.nextToken();
    }

    String nextString() {
        try {
            return br.readLine();
        } catch (IOException e) {
            eof = true;
            return null;
        }
    }

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

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

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


import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.StringTokenizer;

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author Andy Phan
 */
public class p1173e {
    static int MOD = 998244353;
    static int n;
    static int m;
    static long[] invert;
    static long[][] f;
    static long[][] g;
    static boolean[][] df;
    static boolean[][] dg;
    static int[] sum;
    public static void main(String[] args) {
        FS in = new FS(System.in);
        PrintWriter out = new PrintWriter(System.out);
        n = in.nextInt();
        m = in.nextInt();
        invert = new long[2*m];
        int[] like = new int[n];
        sum = new int[2];
        int[] weight = new int[n];
        for(int i = 0; i < n; i++) like[i] = in.nextInt();
        for(int i = 0; i < n; i++) {
            weight[i] = in.nextInt();
            sum[1-like[i]] += weight[i];
        }
        for(int i = -(m-1); i < m; i++) invert[i+m-1] = modInv(sum[0]+sum[1]+i, MOD);
        f = new long[m][m];
        g = new long[m][m];
        df = new boolean[m][m];
        dg = new boolean[m][m];
        for(int i = 0; i < n; i++) if(like[i] == 0) out.println((g(0, 0)*weight[i])%MOD); else System.out.println((f(0, 0)*weight[i])%MOD);
        out.close();
    }

    static long f(int i, int j) {
        if(i+j == m) return 1;
        if(df[i][j]) return f[i][j];
        df[i][j] = true;
        return f[i][j] = (((((sum[0]+i+1)*invert[i-j+m-1])%MOD)*f(i+1, j))%MOD+((((sum[1]-j)*invert[i-j+m-1])%MOD)*f(i, j+1))%MOD)%MOD;
    }

    static long g(int i, int j) {
        if(i+j == m) return 1;
        if(dg[i][j]) return g[i][j];
        dg[i][j] = true;
        return g[i][j] = (((((sum[0]+i)*invert[i-j+m-1])%MOD)*g(i+1, j))%MOD+((((sum[1]-j-1)*invert[i-j+m-1])%MOD)*g(i, j+1))%MOD)%MOD;
    }

    //@
    static long gcd(long a, long b) { return b == 0 ? a : gcd(b, a % b); }
    static long lcm(long a, long b) { return a / gcd(a, b) * b; }

    //@
    // Computes the modular inverse of x
    // Returns 0 if the GCD of x and mod is not 1
    // O(log n)  :  Can be converted to use BigIntegers
    static long modInv(long x, long mod) {
            if(x == 1) return 1;
            if(gcd(x, mod) != 1) return 0;
            long r = mod % x;
            return (modInv(r, x % r, 0, 1, mod / x, x / r)+mod)%mod;
    }

    static long modInv(long a, long b, long y0, long y1, long q0, long q1) {
            long y2 = y0 - y1*q0;
            return b == 0 ? y2 : modInv(b, a % b, y1, y2, q1, a / b);
    }
    static class FS {
        BufferedReader in;
        StringTokenizer t;

        public FS(InputStream i) {
            in = new BufferedReader(new InputStreamReader(i));
        }

        public String next() {
            try {
                while(t == null || !t.hasMoreElements()) {
                    t = new StringTokenizer(in.readLine());
                }
            } catch(Exception e) {}
            return t.nextToken();
        }

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


import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.StringTokenizer;

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author Andy Phan
 */
public class p1173e {
    static int MOD = 998244353;
    static int n;
    static int m;
    static long[] invert;
    static long[][] f;
    static long[][] g;
    static boolean[][] df;
    static boolean[][] dg;
    static int[] sum;
    public static void main(String[] args) {
        FS in = new FS(System.in);
        PrintWriter out = new PrintWriter(System.out);
        n = in.nextInt();
        m = in.nextInt();
        invert = new long[2*m];
        int[] like = new int[n];
        sum = new int[2];
        int[] weight = new int[n];
        for(int i = 0; i < n; i++) like[i] = in.nextInt();
        for(int i = 0; i < n; i++) {
            weight[i] = in.nextInt();
            sum[1-like[i]] += weight[i];
        }
        for(int i = -(m-1); i < m; i++) invert[i+m-1] = modInv(sum[0]+sum[1]+i, MOD);
        f = new long[m][m];
        g = new long[m][m];
        df = new boolean[m][m];
        dg = new boolean[m][m];
        for(int i = 0; i < n; i++) if(like[i] == 0) out.println((g(0, 0)*weight[i])%MOD); else out.println((f(0, 0)*weight[i])%MOD);
        out.close();
    }

    static long f(int i, int j) {
        if(i+j == m) return 1;
        if(df[i][j]) return f[i][j];
        df[i][j] = true;
        return f[i][j] = (((((sum[0]+i+1)*invert[i-j+m-1])%MOD)*f(i+1, j))%MOD+((((sum[1]-j)*invert[i-j+m-1])%MOD)*f(i, j+1))%MOD)%MOD;
    }

    static long g(int i, int j) {
        if(i+j == m) return 1;
        if(dg[i][j]) return g[i][j];
        dg[i][j] = true;
        return g[i][j] = (((((sum[0]+i)*invert[i-j+m-1])%MOD)*g(i+1, j))%MOD+((((sum[1]-j-1)*invert[i-j+m-1])%MOD)*g(i, j+1))%MOD)%MOD;
    }

    //@
    static long gcd(long a, long b) { return b == 0 ? a : gcd(b, a % b); }
    static long lcm(long a, long b) { return a / gcd(a, b) * b; }

    //@
    // Computes the modular inverse of x
    // Returns 0 if the GCD of x and mod is not 1
    // O(log n)  :  Can be converted to use BigIntegers
    static long modInv(long x, long mod) {
            if(x == 1) return 1;
            if(gcd(x, mod) != 1) return 0;
            long r = mod % x;
            return (modInv(r, x % r, 0, 1, mod / x, x / r)+mod)%mod;
    }

    static long modInv(long a, long b, long y0, long y1, long q0, long q1) {
            long y2 = y0 - y1*q0;
            return b == 0 ? y2 : modInv(b, a % b, y1, y2, q1, a / b);
    }
    static class FS {
        BufferedReader in;
        StringTokenizer t;

        public FS(InputStream i) {
            in = new BufferedReader(new InputStreamReader(i));
        }

        public String next() {
            try {
                while(t == null || !t.hasMoreElements()) {
                    t = new StringTokenizer(in.readLine());
                }
            } catch(Exception e) {}
            return t.nextToken();
        }

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


package com.jardon.pg.algorithm.codeforce.r4xx.r480;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.PriorityQueue;
import java.util.StringTokenizer;

import static java.util.Collections.reverse;

/**
 * @author Don Li
 */
public class CactusToTree {

    int N = (int) 5e5 + 10;

    int n, m;
    int[][][] G;

    int timer = 0;
    int[] tin = new int[N], low = new int[N];
    boolean[] bridge = new boolean[N * 2];

    int nc = 0;
    boolean[] vis = new boolean[N];
    int[] vertex_to_cycle = new int[N];
    List<Integer>[] cycle = new List[N];

    int[] par = new int[N];
    int[] len = new int[N];
    int[] L = new int[N];
    int[] Z = new int[N];

    void solve() {
        n = in.nextInt(); m = in.nextInt();
        int[] fr = new int[m], to = new int[m], wt = new int[m];
        for (int i = 0; i < m; i++) {
            fr[i] = in.nextInt() - 1;
            to[i] = in.nextInt() - 1;
            wt[i] = i;
        }
        G = build_graph(n, fr, to, wt);

        mark_bridges(0, -1);

        for (int i = 0; i < n; i++) {
            if (!vis[i]) {
                cycle[nc] = new ArrayList<>();
                dfs(i, nc++);
            }
        }

        create_spanning_tree_and_init_l(0);

        solve_cycle(0, -1, 0);

        for (int i = 0; i < n; i++) {
            if (i > 0) out.print(' ');
            out.print(Math.max(L[i], Z[i]));
        }
    }

    void solve_cycle(int u, int p, int carry) {
        L[u] = Math.max(L[u], carry);

        int id = vertex_to_cycle[u]; int k = cycle[id].size();
        for (int it = 0; it < 2; it++) {
            PriorityQueue<int[]> qu = new PriorityQueue<>((a, b) -> {
                if (a[0] != b[0]) return -Integer.compare(a[0], b[0]);
                return -Integer.compare(a[1], b[1]);
            });
            for (int i = 0; i < 2 * k; i++) {
                int d = 2 * k - i;
                while (!qu.isEmpty() && qu.peek()[1] > d + k / 2) qu.poll();
                if (!qu.isEmpty()) Z[cycle[id].get(i % k)] = Math.max(Z[cycle[id].get(i % k)], qu.peek()[0] - d);
                qu.offer(new int[]{L[cycle[id].get(i % k)] + d, d});
            }
            reverse(cycle[id]);
        }

        for (int v : cycle[id]) {
            int fi = 0, se = 0;
            for (int[] t : G[v]) {
                int w = t[0], e = t[1];
                if (w != p && bridge[e]) {
                    if (fi < 1 + len[w]) {
                        se = fi;
                        fi = 1 + len[w];
                    } else if (se < 1 + len[w]) {
                        se = 1 + len[w];
                    }
                }
            }
            for (int[] t : G[v]) {
                int w = t[0], e = t[1];
                if (w != p && bridge[e]) {
                    int passValue = Math.max(carry, Z[v]);
                    if (1 + len[w] == fi) passValue = Math.max(passValue, se);
                    else passValue = Math.max(passValue, fi);
                    solve_cycle(w, v, passValue + 1);
                }
            }
        }
    }

    void create_spanning_tree_and_init_l(int s) {
        int[] qu = new int[n]; boolean[] inq = new boolean[n];
        int qh = 0, qt = 0;
        qu[qt++] = s;
        inq[s] = true;
        par[s] = -1;
        while (qh < qt) {
            int u = qu[qh++];
            for (int[] t : G[u]) {
                int v = t[0];
                if (!inq[v]) {
                    qu[qt++] = v;
                    inq[v] = true;
                    par[v] = u;
                }
            }
        }

        for (int i = n - 1; i >= 0; i--) {
            int u = qu[i];
            for (int[] t : G[u]) {
                int v = t[0], e = t[1];
                if (par[v] == u) {
                    len[u] = Math.max(len[u], len[v] + 1);
                    if (bridge[e]) L[u] = Math.max(L[u], len[v] + 1);
                }
            }
        }
    }

    void dfs(int u, int id) {
        vis[u] = true;
        vertex_to_cycle[u] = id;
        cycle[id].add(u);
        for (int[] t : G[u]) {
            int v = t[0], e = t[1];
            if (!bridge[e] && !vis[v]) {
                dfs(v, id);
            }
        }
    }

    void mark_bridges(int u, int p) {
        low[u] = tin[u] = ++timer;
        for (int[] t : G[u]) {
            int v = t[0], e = t[1];
            if (tin[v] == 0) {
                mark_bridges(v, u);
                low[u] = Math.min(low[u], low[v]);
                if (low[v] > tin[u]) bridge[e] = true;
            } else if (v != p) {
                low[u] = Math.min(low[u], tin[v]);
            }
        }
    }

    int[][][] build_graph(int n, int[] from, int[] to, int[] weight) {
        int[][][] G = new int[n][][];
        int[] cnt = new int[n];
        for (int i = 0; i < from.length; i++) {
            cnt[from[i]]++;
            cnt[to[i]]++;
        }
        for (int i = 0; i < n; i++) G[i] = new int[cnt[i]][];
        for (int i = 0; i < from.length; i++) {
            G[from[i]][--cnt[from[i]]] = new int[]{to[i], weight[i]};
            G[to[i]][--cnt[to[i]]] = new int[]{from[i], weight[i]};
        }
        return G;
    }

    public static void main(String[] args) {
        in = new FastScanner(new BufferedReader(new InputStreamReader(System.in)));
        out = new PrintWriter(System.out);
        new CactusToTree().solve();
        out.close();
    }

    static FastScanner in;
    static PrintWriter out;

    static class FastScanner {
        BufferedReader in;
        StringTokenizer st;

        public FastScanner(BufferedReader in) {
            this.in = in;
        }

        public String nextToken() {
            while (st == null || !st.hasMoreTokens()) {
                try {
                    st = new StringTokenizer(in.readLine());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

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

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

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


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.PriorityQueue;
import java.util.StringTokenizer;

import static java.util.Collections.reverse;

/**
 * @author Don Li
 */
public class CactusToTree {

    int N = (int) 5e5 + 10;

    int n, m;
    int[][][] G;

    int timer = 0;
    int[] tin = new int[N], low = new int[N];
    boolean[] bridge = new boolean[N * 2];

    int nc = 0;
    boolean[] vis = new boolean[N];
    int[] vertex_to_cycle = new int[N];
    List<Integer>[] cycle = new List[N];

    int[] par = new int[N];
    int[] len = new int[N];
    int[] L = new int[N];
    int[] Z = new int[N];

    void solve() {
        n = in.nextInt(); m = in.nextInt();
        int[] fr = new int[m], to = new int[m], wt = new int[m];
        for (int i = 0; i < m; i++) {
            fr[i] = in.nextInt() - 1;
            to[i] = in.nextInt() - 1;
            wt[i] = i;
        }
        G = build_graph(n, fr, to, wt);

        mark_bridges(0, -1);

        for (int i = 0; i < n; i++) {
            if (!vis[i]) {
                cycle[nc] = new ArrayList<>();
                dfs(i, nc++);
            }
        }

        create_spanning_tree_and_init_l(0);

        solve_cycle(0, -1, 0);

        for (int i = 0; i < n; i++) {
            if (i > 0) out.print(' ');
            out.print(Math.max(L[i], Z[i]));
        }
    }

    void solve_cycle(int u, int p, int carry) {
        L[u] = Math.max(L[u], carry);

        int id = vertex_to_cycle[u]; int k = cycle[id].size();
        for (int it = 0; it < 2; it++) {
            PriorityQueue<int[]> qu = new PriorityQueue<>((a, b) -> {
                if (a[0] != b[0]) return -Integer.compare(a[0], b[0]);
                return -Integer.compare(a[1], b[1]);
            });
            for (int i = 0; i < 2 * k; i++) {
                int d = 2 * k - i;
                while (!qu.isEmpty() && qu.peek()[1] > d + k / 2) qu.poll();
                if (!qu.isEmpty()) Z[cycle[id].get(i % k)] = Math.max(Z[cycle[id].get(i % k)], qu.peek()[0] - d);
                qu.offer(new int[]{L[cycle[id].get(i % k)] + d, d});
            }
            reverse(cycle[id]);
        }

        for (int v : cycle[id]) {
            int fi = 0, se = 0;
            for (int[] t : G[v]) {
                int w = t[0], e = t[1];
                if (w != p && bridge[e]) {
                    if (fi < 1 + len[w]) {
                        se = fi;
                        fi = 1 + len[w];
                    } else if (se < 1 + len[w]) {
                        se = 1 + len[w];
                    }
                }
            }
            for (int[] t : G[v]) {
                int w = t[0], e = t[1];
                if (w != p && bridge[e]) {
                    int passValue = Math.max(carry, Z[v]);
                    if (1 + len[w] == fi) passValue = Math.max(passValue, se);
                    else passValue = Math.max(passValue, fi);
                    solve_cycle(w, v, passValue + 1);
                }
            }
        }
    }

    void create_spanning_tree_and_init_l(int s) {
        int[] qu = new int[n]; boolean[] inq = new boolean[n];
        int qh = 0, qt = 0;
        qu[qt++] = s;
        inq[s] = true;
        par[s] = -1;
        while (qh < qt) {
            int u = qu[qh++];
            for (int[] t : G[u]) {
                int v = t[0];
                if (!inq[v]) {
                    qu[qt++] = v;
                    inq[v] = true;
                    par[v] = u;
                }
            }
        }

        for (int i = n - 1; i >= 0; i--) {
            int u = qu[i];
            for (int[] t : G[u]) {
                int v = t[0], e = t[1];
                if (par[v] == u) {
                    len[u] = Math.max(len[u], len[v] + 1);
                    if (bridge[e]) L[u] = Math.max(L[u], len[v] + 1);
                }
            }
        }
    }

    void dfs(int u, int id) {
        vis[u] = true;
        vertex_to_cycle[u] = id;
        cycle[id].add(u);
        for (int[] t : G[u]) {
            int v = t[0], e = t[1];
            if (!bridge[e] && !vis[v]) {
                dfs(v, id);
            }
        }
    }

    void mark_bridges(int u, int p) {
        low[u] = tin[u] = ++timer;
        for (int[] t : G[u]) {
            int v = t[0], e = t[1];
            if (tin[v] == 0) {
                mark_bridges(v, u);
                low[u] = Math.min(low[u], low[v]);
                if (low[v] > tin[u]) bridge[e] = true;
            } else if (v != p) {
                low[u] = Math.min(low[u], tin[v]);
            }
        }
    }

    int[][][] build_graph(int n, int[] from, int[] to, int[] weight) {
        int[][][] G = new int[n][][];
        int[] cnt = new int[n];
        for (int i = 0; i < from.length; i++) {
            cnt[from[i]]++;
            cnt[to[i]]++;
        }
        for (int i = 0; i < n; i++) G[i] = new int[cnt[i]][];
        for (int i = 0; i < from.length; i++) {
            G[from[i]][--cnt[from[i]]] = new int[]{to[i], weight[i]};
            G[to[i]][--cnt[to[i]]] = new int[]{from[i], weight[i]};
        }
        return G;
    }

    public static void main(String[] args) {
        in = new FastScanner(new BufferedReader(new InputStreamReader(System.in)));
        out = new PrintWriter(System.out);
        new CactusToTree().solve();
        out.close();
    }

    static FastScanner in;
    static PrintWriter out;

    static class FastScanner {
        BufferedReader in;
        StringTokenizer st;

        public FastScanner(BufferedReader in) {
            this.in = in;
        }

        public String nextToken() {
            while (st == null || !st.hasMoreTokens()) {
                try {
                    st = new StringTokenizer(in.readLine());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

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

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

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