#include <bits/stdc++.h>
using namespace std;
using lint = long long int;
struct fast_ios {
  fast_ios() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    cout << fixed << setprecision(20);
  };
} fast_ios_;
template <typename T>
ostream &operator<<(ostream &os, const vector<T> &vec) {
  os << "[";
  for (auto v : vec) os << v << ",";
  os << "]";
  return os;
}
template <typename T>
ostream &operator<<(ostream &os, const set<T> &vec) {
  os << "{";
  for (auto v : vec) os << v << ",";
  os << "}";
  return os;
}
struct DirectedGraphSCC {
  int V;
  std::vector<std::vector<int>> to, from;
  std::vector<int> used;
  std::vector<int> vs;
  std::vector<int> cmp;
  int scc_num = -1;
  DirectedGraphSCC(int V = 0) : V(V), to(V), from(V), cmp(V) {}
  void _dfs(int v) {
    used[v] = true;
    for (auto t : to[v])
      if (!used[t]) _dfs(t);
    vs.push_back(v);
  }
  void _rdfs(int v, int k) {
    used[v] = true;
    cmp[v] = k;
    for (auto t : from[v])
      if (!used[t]) _rdfs(t, k);
  }
  void add_edge(int from_, int to_) {
    assert(from_ >= 0 and from_ < V and to_ >= 0 and to_ < V);
    to[from_].push_back(to_);
    from[to_].push_back(from_);
  }
  int FindStronglyConnectedComponents() {
    used.assign(V, false);
    vs.clear();
    for (int v = 0; v < V; v++)
      if (!used[v]) _dfs(v);
    used.assign(V, false);
    scc_num = 0;
    for (int i = (int)vs.size() - 1; i >= 0; i--)
      if (!used[vs[i]]) _rdfs(vs[i], scc_num++);
    return scc_num;
  }
  DirectedGraphSCC GenerateTopologicalGraph() {
    DirectedGraphSCC newgraph(scc_num);
    for (int s = 0; s < V; s++)
      for (auto t : to[s]) {
        if (cmp[s] != cmp[t]) newgraph.add_edge(cmp[s], cmp[t]);
      }
    return newgraph;
  }
};
int main() {
  int N;
  cin >> N;
  DirectedGraphSCC g(N);
  for (int i = (0), i_end_ = (N); i < i_end_; i++) {
    string S;
    cin >> S;
    for (int j = (0), j_end_ = (N); j < j_end_; j++)
      if (S[j] == '1') g.add_edge(i, j);
  }
  int nscc = g.FindStronglyConnectedComponents();
  if (nscc <= 1) {
    puts("0 1");
    return 0;
  }
  int ret = 0;
  for (int i = (0), i_end_ = (N); i < i_end_; i++) {
    vector<int> ord(N);
    for (int j = (0), j_end_ = (N); j < j_end_; j++) ord[j] = g.to[j].size();
    ord[i] = N - 1 - ord[i];
    for (auto t : g.to[i]) ord[t]++;
    for (auto f : g.from[i]) ord[f]--;
    sort(ord.begin(), ord.end());
    int e = 0;
    ret++;
    for (int i = (0), i_end_ = (N - 1); i < i_end_; i++) {
      e += ord[i];
      if (e == i * (i + 1) / 2) {
        ret--;
        break;
      }
    }
  }
  if (ret) {
    cout << "1 " << ret << endl;
    return 0;
  }
  if (nscc == 2) {
    lint n0 = 0, n1 = 0;
    for (int i = (0), i_end_ = (N); i < i_end_; i++) (g.cmp[i] ? n1 : n0)++;
    if (N == 4 and n0 * n1 == 3) {
      puts("-1");
      return 0;
    }
    cout << "2 " << n0 * n1 * 2 % 998244353 << endl;
  }
}
