#include <bits/stdc++.h>
int constexpr maxN = 18;
int number;
std::vector<int> getBlocks(int mask) {
  int cur = 1;
  std::vector<int> blocks;
  for (int bit = 0; bit < number; ++bit) {
    if (mask >> bit & 1) {
      ++cur;
    } else {
      if (cur != 1) blocks.push_back(cur);
      cur = 1;
    }
  }
  assert(cur == 1);
  std::sort(begin(blocks), end(blocks));
  return blocks;
}
auto const factorial = [] {
  std::array<int64_t, 19> factorial{{1}};
  for (int i = 1; i < (int)factorial.size(); ++i)
    factorial[i] = factorial[i - 1] * i;
  return factorial;
}();
std::vector<int64_t> count;
std::map<std::vector<int>, int64_t> memory;
std::vector<int64_t> chain;
std::vector<std::vector<int>> withPop;
std::vector<std::array<int64_t, maxN>> countWithLast;
std::vector<int> add;
void work(std::vector<int> cur, int curSum) {
  assert(curSum == std::accumulate(begin(cur), end(cur), 0));
  int64_t result{};
  if (curSum == 0) {
    assert(count[0] == 1);
  }
  for (auto mask : withPop[curSum]) result += count[mask];
  result *= factorial[number - curSum];
  if (curSum + 2 <= number) {
    for (auto mask : withPop[curSum + 1]) countWithLast[mask].fill(0);
    for (auto mask : withPop[curSum])
      if (count[mask])
        for (auto tmp = ((1 << number) - 1) ^ mask; tmp; tmp -= tmp & -tmp)
          countWithLast[mask | (tmp & -tmp)][__builtin_ctz(tmp)] = count[mask];
    for (int next = 2; next <= number - curSum; ++next) {
      for (auto mask : withPop[curSum + next]) countWithLast[mask].fill(0);
      for (auto mask : withPop[curSum + next - 1])
        for (int tmp = mask; tmp; tmp -= tmp & -tmp) {
          int const last = __builtin_ctz(tmp);
          if (auto const cur = countWithLast[mask][last]) {
            for (int tmp = (((1 << number) - 1) ^ mask) & add[last]; tmp;
                 tmp -= tmp & -tmp) {
              countWithLast[mask | (tmp & -tmp)][__builtin_ctz(tmp)] += cur;
            }
          }
        }
      if (cur.empty() or next >= cur.back()) {
        for (auto mask : withPop[curSum + next])
          count[mask] = std::accumulate(begin(countWithLast[mask]),
                                        end(countWithLast[mask]), (int64_t)0);
        work(
            [next, tmp = cur]() mutable {
              tmp.push_back(next);
              return std::move(tmp);
            }(),
            curSum + next);
      }
    }
  }
  memory[std::move(cur)] = result;
}
int main() {
  std::ios::sync_with_stdio(0);
  std::cin.tie(0);
  std::cin >> number;
  countWithLast.resize(1 << number);
  withPop.push_back({0});
  while ((int)withPop.size() <= number) {
    withPop.emplace_back();
    for (auto it : withPop.end()[-2]) {
      for (int nextBit = 1; (nextBit & it) == 0 and nextBit < (1 << number);
           nextBit <<= 1)
        withPop.back().push_back(it | nextBit);
    }
  }
  assert(number <= maxN);
  add.resize(number);
  for (int& row : add) {
    for (int bit = 0; bit < number; ++bit) {
      char ch;
      std::cin >> ch;
      row |= (ch - '0') << bit;
    };
  }
  chain = [&] {
    std::vector<int64_t> chain(1 << number);
    std::vector<std::array<int64_t, maxN>> value(1 << number);
    for (int bit = 0; bit < number; ++bit) value[1 << bit][bit] = 1;
    for (int subset = 1; subset < (int)value.size(); ++subset) {
      auto const subsetLength = __builtin_popcount(subset);
      auto& cur = value[subset];
      for (auto tmp = subset; tmp; tmp -= tmp & -tmp) {
        auto const last = __builtin_ctz(tmp);
        if (auto const cur1 = cur[last]; cur1 != 0) {
          chain[subset] += cur1;
          int tmp = (((1 << number) - 1) ^ subset) & add[last];
          for (; tmp; tmp -= tmp & -tmp) {
            value[subset | (tmp & -tmp)][__builtin_ctz(tmp)] += cur1;
          }
        }
      }
    }
    return chain;
  }();
  count.resize(1 << number);
  count[0] = 1;
  work({}, 0);
  std::vector<int64_t> result(1 << (number - 1));
  for (int mask = 0; mask < (int)result.size(); ++mask) {
    result[mask] = memory.at(getBlocks(mask));
  }
  for (int dim = 0; dim < number - 1; ++dim)
    for (int mask = 0; mask < (int)result.size(); ++mask)
      if (not(mask >> dim & 1)) {
        result[mask] -= result[mask | 1 << dim];
        assert(result[mask] >= 0);
      }
  for (auto it : result) std::cout << it << ' ';
  std::cout << '\n';
}
