Let's assume that we are given a matrix b of size x × y, let's determine the operation of mirroring matrix b. The mirroring of matrix b is a 2x × y matrix c which has the following properties:

  * the upper half of matrix c (rows with numbers from 1 to x) exactly matches b; 
  * the lower half of matrix c (rows with numbers from x + 1 to 2x) is symmetric to the upper one; the symmetry line is the line that separates two halves (the line that goes in the middle, between rows x and x + 1). 



Sereja has an n × m matrix a. He wants to find such matrix b, that it can be transformed into matrix a, if we'll perform on it several (possibly zero) mirrorings. What minimum number of rows can such matrix contain?

Input

The first line contains two integers, n and m (1 ≤ n, m ≤ 100). Each of the next n lines contains m integers — the elements of matrix a. The i-th line contains integers ai1, ai2, ..., aim (0 ≤ aij ≤ 1) — the i-th row of the matrix a.

Output

In the single line, print the answer to the problem — the minimum number of rows of matrix b.

Examples

Input

4 3
0 0 1
1 1 0
1 1 0
0 0 1


Output

2


Input

3 3
0 0 0
0 0 0
0 0 0


Output

3


Input

8 1
0
1
1
0
0
1
1
0


Output

2

Note

In the first test sample the answer is a 2 × 3 matrix b:
    
    
      
    001  
    110  
    

If we perform a mirroring operation with this matrix, we get the matrix a that is given in the input:
    
    
      
    001  
    110  
    110  
    001  
    
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Scanner;
import java.util.Set;
import java.util.Stack;
import java.util.StringTokenizer;
import java.util.TreeSet;
public class Main {
	//YOU CAN DO IT ....
	//Do what you love to do and give it your very best. Whether it's business or baseball, or the theater, or any field.
	//If you don't love what you're doing and you can't give it your best, get out of it. Life is too short. You'll be an old man before you know it.
	//Don't aim for success if you want it; just do what you love and believe in, and it will come naturally.
static int n; static int m; static int ans;static long count; static int flag;
static int a[];static int seg[];static boolean isPrime[];static boolean visited[] ;static int dp[][];
static ArrayList<pair> s[];static ArrayList<Integer>list;
static class pair{String first;int second;public pair(String x,int y){first=x;second=y;}}
static void seive(){isPrime[0] = isPrime[1] = true;for (int i = 2; i*i <= 2000000; i++) {if(isPrime[(int) i]) { long j=0; for ( j = i*i; j <= 2000000; j += i)isPrime[(int) j] = true;}}}
static int V;
static ArrayList<Edge>[] adjList;

static int[] dijkstra(int S, int T)
{
	long[] dist = new long[V];
	int[] p = new int[V];
	Arrays.fill(dist, (long)1e16);
	Arrays.fill(p, -1);
	dist[S] = 0;
	
	PriorityQueue<Edge> pq = new PriorityQueue<Edge>();
	pq.add(new Edge(S, 0));
	while(!pq.isEmpty())
	{
		Edge cur = pq.remove();//awal node
		if(cur.to == T)
			return p;
		if(cur.cost > dist[cur.to])
			continue;
		for(Edge nxt: adjList[cur.to])
			if(nxt.cost + cur.cost < dist[nxt.to])
			{
				pq.add(new Edge(nxt.to, dist[nxt.to] = nxt.cost + cur.cost));
				p[nxt.to] = cur.to;
			}
	}
	return null;
}
    public static void main(String[] args) throws FileNotFoundException {
    	Scanner sc = new Scanner(System.in);

		int n = sc.nextInt(), m = sc.nextInt();
		int[][] a = new int[n][m];
		for(int i = 0; i < n; ++i)
			for(int j = 0; j < m; ++j)
				a[i][j] = sc.nextInt();
		int y[]={1,3,4};
		
		int rows = n;
		while(cut(a, rows))
			rows /= 2;
		System.out.println(rows);
		
	}
	
	static boolean cut(int[][] a, int rows)
	{
		if(rows%2==1)return false;
		for(int i=0;i<rows/2;i++)
		{
			if(!match(a[i],a[rows-i-1]))
				return false;
				
		}
		return true;
		
	}
	
	static boolean match(int[] x, int[] y)
	{
		for(int i = 0; i < x.length; ++i)
			if(x[i] != y[i])
				return false;
		return true;
	}
    	
    	
    	
    	
    	
    	
    	
    	
    	
    	
    	
    	
    	
    	
    	}
    	
    

class Edge implements Comparable<Edge>
{
	int to;//second node
	long cost;//weight
	
	Edge(int x, long y)
	{
		to = x;
		cost = y;
	}
	
	public int compareTo(Edge e)
	{
		if(cost != e.cost)
			return cost > e.cost ? 1 : -1;
		return 0;		
	}
}
   class couple implements Comparable<couple>
   { String x;
   int y;
     public couple(String m,int f) {
    	 x=m;
    	 y=f;
     }
	public int compareTo(couple o) {
		
		 
		return y-o.y;
	}
	static class Scanner 
	{
		StringTokenizer st;
		BufferedReader br;

		public Scanner(InputStream s){    br = new BufferedReader(new InputStreamReader(s));}

		public Scanner(FileReader r){    br = new BufferedReader(r);}

		public String next() throws IOException 
		{
			while (st == null || !st.hasMoreTokens()) 
				st = new StringTokenizer(br.readLine());
			return st.nextToken();
		}

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

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

		public String nextLine() throws IOException {return br.readLine();}

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

		public boolean ready() throws IOException {return br.ready();}


	}
} 