#include <bits/stdc++.h>
using namespace std;
const long long M = 1e9 + 7;
const long long mod = 998244353;
mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
long long binpow(long long a, long long b) {
  long long res = 1;
  while (b > 0) {
    if (b & 1) res = res * a % mod;
    a = a * a % mod;
    b >>= 1;
  }
  return res;
}
long long gcd(long long a, long long b) { return (b == 0 ? a : gcd(b, a % b)); }
long long c_root = 3;
long long inv_mod(long long base) { return binpow(base, mod - 2); }
void ntt(vector<long long> &a, bool inv) {
  int n = (int)a.size();
  if (n == 1) return;
  for (int i = 0, j = 0; i < n; i++) {
    if (i > j) {
      swap(a[i], a[j]);
    }
    for (int l = n / 2; (j ^= l) < l; l >>= 1)
      ;
  }
  for (int sz = 1; sz < n; sz <<= 1) {
    long long delta = binpow(c_root, (mod - 1) / (2 * sz));
    if (inv) {
      delta = inv_mod(delta);
    }
    for (int i = 0; i < n; i += 2 * sz) {
      long long w = 1;
      for (int j = 0; j < sz; j++) {
        long long u = a[i + j], v = w * a[i + j + sz] % mod;
        a[i + j] = (u + v + mod) % mod;
        a[i + j] = (a[i + j] + mod) % mod;
        a[i + j + sz] = (u - v + mod) % mod;
        a[i + j + sz] = (a[i + j + sz] + mod) % mod;
        w = w * delta % mod;
      }
    }
  }
  if (inv) {
    long long inv_n = inv_mod(n);
    for (int i = 0; i < n; i++) {
      a[i] = a[i] * inv_n % mod;
    }
  }
  for (int i = 0; i < n; i++) {
    a[i] %= mod;
    a[i] = (a[i] + mod) % mod;
  }
}
vector<long long> convolution(vector<long long> &a, vector<long long> &b) {
  int lim = (int)max(a.size(), b.size());
  int n = 1;
  while (n < lim) n <<= 1;
  n <<= 1;
  a.resize(n);
  b.resize(n);
  vector<long long> c(n);
  ntt(a, false);
  ntt(b, false);
  for (int i = 0; i < n; i++) {
    c[i] = a[i] * b[i] % mod;
  }
  ntt(c, true);
  return c;
}
struct dsu {
  int n;
  vector<int> p, sz, e;
  vector<vector<long long>> dp;
  dsu() {}
  dsu(int n) : n(n) {
    p = sz = e = vector<int>(n);
    for (int i = 0; i < n; i++) p[i] = i, sz[i] = 1;
    dp.assign(n, {0, 1});
  }
  int find(int u) { return u == p[u] ? u : p[u] = find(p[u]); };
  void merge(int u, int v) {
    u = find(u);
    v = find(v);
    if (u != v) {
      if (sz[u] < sz[v]) swap(u, v);
      sz[u] += sz[v];
      e[u] += e[v] + 1;
      p[v] = u;
      dp[u] = convolution(dp[u], dp[v]);
      dp[u].resize(sz[u] + 1);
      dp[v].clear();
      if (e[u] == sz[u] * (sz[u] - 1) / 2) dp[u][1] = 1;
    } else {
      e[u]++;
      if (e[u] == sz[u] * (sz[u] - 1) / 2) dp[u][1] = 1;
    }
  }
  int operator[](int u) { return find(u); }
};
void solve() {
  int n;
  cin >> n;
  vector<tuple<int, int, int>> edges;
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < n; j++) {
      int x;
      cin >> x;
      if (i < j) edges.emplace_back(x, i, j);
    }
  }
  sort(edges.begin(), edges.end());
  dsu d(n);
  for (auto &[c, a, b] : edges) {
    d.merge(a, b);
  }
  for (int i = 1; i <= n; i++) {
    cout << d.dp[d[0]][i] << " ";
  }
  cout << '\n';
}
int32_t main() {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  int t = 1;
  while (t--) {
    solve();
  }
}
