#include <bits/stdc++.h>
using namespace std;
const int oo = 0x3f3f3f3f;
const double eps = 1e-9;
int A, B;
string grid[30];
vector<string> rotate(vector<string> v) {
  int x = int((v).size()), y = int((v[0]).size());
  vector<string> vv(y, string(x, ' '));
  for (int i = (0); i < (y); i++)
    for (int j = (0); j < (x); j++) vv[i][j] = v[x - j - 1][i];
  return vv;
}
vector<string> getsmallest(vector<string> v) {
  vector<string> best = v;
  for (int i = (0); i < (3); i++) {
    v = rotate(v);
    best = min(best, v);
  }
  return best;
}
bool good(int X, int Y) {
  vector<vector<string> > pieces;
  for (int i = 0; i < A; i += X)
    for (int j = 0; j < B; j += Y) {
      vector<string> cur;
      for (int k = (i); k < (i + X); k++) cur.push_back(grid[k].substr(j, Y));
      cur = getsmallest(cur);
      pieces.push_back(cur);
    }
  sort((pieces).begin(), (pieces).end());
  for (int i = (0); i < (int((pieces).size()) - 1); i++)
    if (pieces[i] == pieces[i + 1]) return false;
  return true;
}
int main() {
  cin >> A >> B;
  for (int i = (0); i < (A); i++) cin >> grid[i];
  pair<int, int> res(A, B);
  int num = 0;
  for (int X = (1); X < (A + 1); X++)
    for (int Y = (1); Y < (B + 1); Y++) {
      if (A % X || B % Y) continue;
      if (good(X, Y)) {
        num++;
        if (X * Y < res.first * res.second ||
            (X * Y == res.first * res.second && X < res.first))
          res = pair<int, int>(X, Y);
      }
    }
  cout << num << endl << res.first << ' ' << res.second << endl;
  return 0;
}
