//* Problem  : Problem G: Squadtrees
//* Contest  : ECNA - 2003
//* Type     : Solution
//* Date     : 2008.08.15
//* Author   : alt
//* Language : C++
//* Compiler : Microsoft Visual C++ 6.0

#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <vector>
#include <queue>
#include <string>
#include <stack>
#include <set>
#include <map>
#include <algorithm>

using namespace std;

// BEGIN CUT HERE
// types
typedef long long int64;
typedef unsigned long long uint64;
typedef pair <int,int> PII;
typedef vector <int> VI;
typedef vector <int64> VI64;
typedef vector <string> VS;
typedef vector <vector<string> > VVS;
typedef vector <vector<int> > VVI;
typedef vector <pair<int,int> > VPII;
typedef vector <vector<pair<int,int> > > VVPII;
typedef map<int,int> MII;
typedef map<string,int> MSI;
typedef queue<int> QI;
//loops
#define FOR(i, n) for (int i = 0; i < (int)n; i++)
#define FORR(i, n) for (int i = (int)(n)-1; i >= 0; i--)
#define FORE(i, a, b) for (int i = (int)(a); i <= (int)(b); i++)
#define FORER(i, a, b) for (int i = (int)(a); i >= int(b); i--)
#define FORSZ(i, a) FOR(i, SZ(a))
#define FORSZR(i, a) FORR(SZ(a), i)
#define FORO(i, x) for (typeof((x).begin()) i = (x).begin(); i != (x).end(); i++)
#define FOROR(i, x) for (typeof((x).end()) i = (x).end(); i != (x).begin(); i--)
#define REP(n) for (int _foo = (int)n - 1; _foo >= 0; _foo--)

#define VAR(a, b) typeof(b) a=(b)
#define FOREACH(it, c) for(VAR(it,(c).begin()); it!=(c).end(); it++)
//sorting & c
#define ALL(a) a.begin(), a.end()
#define RALL(a) a.rbegin(), a.rend()
#define SORT(a) sort(ALL(a))
#define RSORT(a) sort(RALL(a))
#define UNIQUE(c) SORT(c),(c).resize(unique(ALL(c))-(c).begin())
#define REVERSE(a) reverse(ALL(a))
//filling
#define FILLA(a,val) memset(a, val, sizeof(a))
#define FILLO(o,val) memset(&o, val, sizeof(o))
#define CLEARA(a) FILLA(a, 0)
#define CLEARO(a) FILLO(a, 0)
//misc
#define X first
#define Y second
#define MP make_pair
#define PB push_back
#define SZ(a) (int)a.size()
#define POP(a) a.top(), a.pop()
#define FRONT(a) a.front(), a.pop()
//const
const int INF = 1000000000;
const int64 INFL = 1000000000000000000LL;
const double PI =	acos(-1.0);
const double EPS = 1E-6;

/*template<class T> T& operator >?= (T &x, T y) {if(y>x) x=y; return x;}
template<class T> T& operator <?= (T &x, T y) {if(y<x) x=y; return x;}
template<class T> T operator >? (T x, T y) {return x>y?x:y;}
template<class T> T operator <? (T x, T y) {return x<y?x:y;}*/

//some math
template <typename T> inline T gcd(T a, T b)				{ return b ? gcd(b, a % b) : a; }
template <typename T> inline T gcd2(T a, T b)				{ while (a && b) if (a > b) a %= b; else b %= a; return (a + b);}
template <typename T> inline T lcm(T a, T b)				{ return a / gcd(a, b) * b; }
template <typename T> inline T abs(T a)					{ return a < 0 ? -a : a; }
template <typename T> inline T sqr(T a)					{ return a * a; }
template <typename T> inline double hypot(T a, T b)		{ return sqrt(1.0 * a * a + b * b);}
//template <typename T> inline double hypot(T a, T b, T ñ)	{ return sqrt(1.0 * a * a + b * b + ñ * ñ);}
template <typename T> inline T hypot2(T a, T b)			{ return a * a + b * b;}
//template <typename T> inline T hypot2(T a, T b, T c)		{ return a * a + b * b + c * c;}
template <typename T> inline void chMin(T& a, T b) { if (b < a) a = b; }
template <typename T> inline void chMax(T& a, T b) { if (b > a) a = b; }

//assertions
#ifdef _DEBUG
#define ASSERT(f) if (!(f)) printf("%s\n", "ASSERTION FAILED!");
#define ASSERTS(f, s) if (!(f)) printf("%s [%s]\n", "ASSERTION FAILED!", s);
#else
#define ASSERT(f) f
#define ASSERTS(f, s) f
#endif

int cmp_int(const void *a, const void *b){return *(int*)a - *(int*)b;}

//input
inline int ri(){int tt; ASSERTS(scanf("%d", &tt) == 1, "ReadInt Failed"); return tt;}
inline int64 ri64(){int64 tt; ASSERTS(scanf("%lld", &tt) == 1, "ReadInt64 Failed"); return tt;}
inline double rd(){double tt; ASSERTS(scanf("%lf", &tt) == 1, "ReadDouble Failed"); return tt;}
inline void rs(char *s){ASSERTS(scanf("%s", s) == 1, "ReadChar* Failed");}
//output
inline void pvi(int *a, int n){FOR(i, n) printf("%d%c", a[i], i == n - 1 ? '\n' : ' ');}
inline void pvi(VI a){FORSZ(i,a) printf("%d%c", a[i], i == a.size() - 1 ? '\n' : ' ');}
inline void pi(int n){printf("%d\n", n);}
inline void pi64(int64 n){printf("%lld\n", n);}
// END CUT HERE

struct tree_item{
	int hash;
	int val;
	int p1;
	int p2;
	int p3;
	int p4;
}list[1000000]; int plist;

int n, m, res1, res2;

int a[128][128], s[128][128];

int sum(int x, int y, int d)
{
	int res = s[x+d-1][y+d-1];
	if (x)
		res -= s[x-1][y+d-1];
	if (y)
		res -= s[x+d-1][y-1];
	if (x && y)
		res += s[x-1][y-1];
	return res;
}

int p[128][128][256];

const int mod = 983;
//vector <vector<int> > v;

int encode1(int x, int y, int d)
{
	int pp = p[x][y][d] = ++plist;
	int sm = sum(x, y, d);
	if (sm == 0 || sm == d * d) 
	{
		list[pp].hash = sm ? 10275479 : 5;
		list[pp].p1 = list[pp].p2 = list[pp].p3 = list[pp].p4 = 0;
		list[pp].val = !!sm;
		return 1;
	}
	int dd = d;
	d /= 2;
	int res = 1;

	list[pp].val = -1;

	int64 hash = 1;
	res += encode1(x, y, d);
	list[pp].p1 = p[x][y][d];
	hash += (113210111699LL * list[list[pp].p1].hash);

	res += encode1(x+d, y, d);
	list[pp].p2 = p[x+d][y][d];
	hash += (26263 * list[list[pp].p2].hash);

	res += encode1(x, y+d, d);
	list[pp].p3 = p[x][y+d][d];
	hash += (9091 * list[list[pp].p3].hash);

	res += encode1(x+d, y+d, d);
	list[pp].p4 = p[x+d][y+d][d];
	hash += (2834483 * list[list[pp].p4].hash);

	list[pp].hash = ((hash >=0 ? hash : -hash) + mod*mod) % mod;
	return res;
}

int eq_trees(int p1, int p2)
{
	if (!p1 && !p2) return 1;
	if (!p1 || !p2) return 0;
	if (list[p1].hash != list[p2].hash) return 0;
	if (list[p1].val != list[p2].val) return 0;
	if (!eq_trees(list[p1].p1, list[p2].p1)) return 0;
	if (!eq_trees(list[p1].p2, list[p2].p2)) return 0;
	if (!eq_trees(list[p1].p3, list[p2].p3)) return 0;
	if (!eq_trees(list[p1].p4, list[p2].p4)) return 0;
	return 1;
}

struct int_list{
	int val, p;
}list2[1000000]; int plist2;

int root[mod];

void add(int r, int v)
{
	int p = ++plist2;
	list2[p].val = v;
	list2[p].p = root[r];
	root[r] = p;
}

int encode2(int x, int y, int d)
{
	int sm = sum(x, y, d);
	if (sm == 0 || sm == d * d) return 1;
	int rem = list[p[x][y][d]].hash;
	int pp = root[rem];
	while (pp)
	{
		if (eq_trees(p[x][y][d], list2[pp].val))
			return 0;
		pp = list2[pp].p;
	}
	add(rem, p[x][y][d]);
	d /= 2;
	return 1 + encode2(x, y, d) + encode2(x, y + d, d) + encode2(x + d, y, d) + encode2(x + d, y + d, d);
}

void solve()
{
	CLEARA(root);
	plist = 0; plist2 = 0;
//	CLEARA(p);

	s[0][0] = a[0][0];
	for (int i = 1; i < n; i++)
		s[0][i] = s[0][i-1] + a[0][i], s[i][0] = s[i-1][0] + a[i][0];
 	for (int i = 1; i < n; i++)
		for (int j = 1; j < n; j++)
			s[i][j] = s[i][j-1] + s[i-1][j] - s[i-1][j-1] + a[i][j];
	res1 = encode1(0, 0, n);
	res2 = encode2(0, 0, n);
}

char ss[1000];

int main()
{
#ifdef _DEBUG
	freopen("1064", "r", stdin);
#endif
	int it = 0;
	while ((n = ri()) && (m = ri()))
	{
		CLEARA(a);
		FOR(i,n)
		{
			scanf("%s", ss);
			FOR(j, m)
				a[i][j] = (ss[j] == '1');
		}
		n = max(n, m);
		int p2;
		for (p2 = 1; p2 < n; p2 *= 2);
		n = p2;
		solve();
		printf("%d %d\n", res1, res2);
	}
	return 0;
}

