#include <bits/stdc++.h>
using namespace std;
using ll = long long int;
const int N = 2e3 + 5;
const int Mod = 998244353;
int root[N], sz[N], edges[N];
vector<vector<int>> ways(N);
int Find(int u) { return root[u] = root[u] == u ? u : Find(root[u]); }
void Merge(int u, int v) {
  u = Find(u);
  v = Find(v);
  if (u == v) {
    ++edges[u];
    if (edges[u] == sz[u] * (sz[u] - 1) / 2) ++ways[u][1];
    return;
  }
  if (sz[u] < sz[v]) swap(u, v);
  vector<int> res(sz[u] + sz[v] + 1);
  for (int i = 0; i <= sz[u]; ++i)
    for (int j = 0; j <= sz[v]; ++j) {
      res[i + j] += (1LL * ways[u][i] * ways[v][j]) % Mod;
      if (res[i + j] >= Mod) res[i + j] -= Mod;
    }
  sz[u] += sz[v];
  root[v] = u;
  edges[u] += edges[v] + 1;
  ways[u] = res;
  if (edges[u] == sz[u] * (sz[u] - 1) / 2) ++ways[u][1];
}
int main() {
  ios::sync_with_stdio(0);
  cin.tie(0);
  int n;
  cin >> n;
  vector<array<int, 3>> cost;
  for (int i = 0; i < n; ++i) {
    for (int j = 0; j < n; ++j) {
      int x;
      cin >> x;
      if (i < j) cost.push_back({x, i, j});
    }
  }
  sort(begin(cost), end(cost));
  for (int i = 0; i < n; ++i) {
    sz[i] = 1;
    root[i] = i;
    ways[i] = {0, 1};
  }
  for (auto [_, u, v] : cost) {
    Merge(u, v);
  }
  vector<int> ans = ways[Find(0)];
  while ((int)ans.size() < n + 1) ans.push_back(0);
  for (int i = 1; i <= n; ++i) cout << ans[i] << ' ';
}
