#include <bits/stdc++.h>
using namespace std;
using ll = long long;
template <class t, class u>
bool chmax(t& first, u second) {
  if (first < second) {
    first = second;
    return true;
  } else
    return false;
}
template <class t, class u>
bool chmin(t& first, u second) {
  if (second < first) {
    first = second;
    return true;
  } else
    return false;
}
template <class t>
using vc = vector<t>;
template <class t, class u>
ostream& operator<<(ostream& os, const pair<t, u>& p) {
  return os << "{" << p.first << "," << p.second << "}";
}
template <class t>
ostream& operator<<(ostream& os, const vc<t>& v) {
  os << "{";
  for (auto e : v) os << e << ",";
  return os << "}";
}
const int INF = 1000000000;
int n, outdeg[8005];
bool ex[8005][8005], rem[8005], reach[8005], isin[8005];
string str[8005];
int conv(char ch) {
  if ('0' <= ch && ch <= '9')
    return ch - '0';
  else
    return 10 + (ch - 'A');
}
int tmp[8005], ran[8005];
void alignment(vc<int>& first) {
  for (auto x : first) {
    for (auto y : first) {
      if (x != y) tmp[x] += ex[x][y];
    }
  }
  sort(first.begin(), first.end(), [](const int& first, const int& second) {
    return tmp[first] < tmp[second];
  });
}
vector<int> Q[8005];
struct seg {
  int s[(1 << 13) * 2];
  void init() { memset(s, 0, sizeof(s)); }
  void update(int i, int x) {
    i += (1 << 13) - 1;
    s[i] = x;
    while (i) {
      i = (i - 1) / 2;
      s[i] = s[i * 2 + 1] + s[i * 2 + 2];
    }
  }
  int get(int first, int second, int k, int l, int r) {
    if (r < first || second < l) return 0;
    if (first <= l && r <= second) return s[k];
    return get(first, second, k * 2 + 1, l, (l + r) / 2) +
           get(first, second, k * 2 + 2, (l + r) / 2 + 1, r);
  }
  int get(int first, int second) {
    return get(first, second, 0, 0, (1 << 13) - 1);
  }
} kaede;
struct seg2 {
  int s[(1 << 13) * 2];
  void init() { fill(s, s + (1 << 13) * 2, INF); }
  void update(int i, int x) {
    i += (1 << 13) - 1;
    s[i] = x;
    while (i) {
      i = (i - 1) / 2;
      s[i] = min(s[i * 2 + 1], s[i * 2 + 2]);
    }
  }
  int get(int first, int second, int k, int l, int r) {
    if (r < first || second < l) return INF;
    if (first <= l && r <= second) return s[k];
    return min(get(first, second, k * 2 + 1, l, (l + r) / 2),
               get(first, second, k * 2 + 2, (l + r) / 2 + 1, r));
  }
  int get(int first, int second) {
    return get(first, second, 0, 0, (1 << 13) - 1);
  }
} fuyuko;
void solve() {
  cin >> n;
  for (int i = int(0); i < int(n); i++) cin >> str[i];
  for (int i = int(0); i < int(n); i++) {
    for (int j = int(0); j < int(n / 4); j++) {
      int v = conv(str[i][j]);
      outdeg[i] += __builtin_popcount(v);
      for (int k = int(0); k < int(4); k++)
        ex[i][(j << 2) ^ k] = ((v >> (3 - k)) & 1);
    }
  }
  int zan = n;
  ll ans = 0;
  while (zan) {
    int v = -1;
    for (int i = int(0); i < int(n); i++) {
      if (rem[i]) continue;
      if (outdeg[i] == zan - 1) v = i;
    }
    if (v == -1) break;
    ans += zan - 1;
    ans += 614LL * n * (zan - 1);
    rem[v] = 1;
    for (int i = int(0); i < int(n); i++) outdeg[i] -= ex[i][v];
    zan--;
  }
  if (zan == 0) {
    cout << ans << endl;
    return;
  }
  int g;
  for (int i = int(0); i < int(n); i++)
    if (!rem[i]) {
      g = i;
      break;
    }
  vc<int> in, out;
  for (int i = int(0); i < int(n); i++)
    if (!rem[i] && g != i) {
      if (ex[i][g]) {
        in.push_back(i);
        isin[i] = 1;
      } else
        out.push_back(i);
    }
  ans += 3LL * (zan - 1) * zan / 2;
  alignment(in);
  alignment(out);
  for (int i = int(0); i < int(in.size()); i++)
    for (int j = int(0); j < int(i); j++) assert(ex[in[i]][in[j]]);
  for (int i = int(0); i < int(out.size()); i++)
    for (int j = int(0); j < int(i); j++) assert(ex[out[i]][out[j]]);
  for (int i = int(0); i < int(in.size()); i++) ran[in[i]] = 1;
  for (auto at : out) {
    int v = -1;
    for (int i = int(0); i < int(in.size()); i++)
      if (ex[at][in[i]]) v = i;
    for (int i = int(0); i < int(in.size()); i++)
      if (i > v && !reach[i]) ans++;
    for (int i = int(0); i < int(in.size()); i++)
      if (ex[at][in[i]]) reach[i] = 1;
  }
  for (auto at : in) {
    for (auto at2 : out)
      if (!ex[at][at2]) goto fail;
    ans++;
  fail:;
  }
  for (auto at : out) {
    for (auto at2 : in)
      if (ex[at][at2]) goto fail2;
    ans++;
  fail2:;
  }
  kaede.init();
  fuyuko.init();
  for (int j = int(0); j < int(in.size()); j++) {
    int at = in[j];
    int mn = INF, mx = -INF, cnt = 0;
    for (int i = int(0); i < int(out.size()); i++) {
      if (ex[at][out[i]]) {
        cnt++;
        chmin(mn, i);
        chmax(mx, i);
      }
    }
    if (cnt == 0) {
      ans += in.size() - 1 - j;
      fuyuko.update(j, out.size());
    } else {
      assert(mx - mn + 1 == cnt && mx == out.size() - 1);
      Q[mn].push_back(j);
      fuyuko.update(j, mn);
    }
  }
  for (int i = int(0); i < int(in.size()); i++) kaede.update(i, 1);
  vector<int> vis(in.size(), 0);
  for (int i = out.size() - 1; i >= 0; i--) {
    for (int j = int(0); j < int(in.size()); j++) {
      if (vis[j] || !ex[out[i]][in[j]]) continue;
      vis[j] = 1;
      kaede.update(j, 0);
    }
    for (auto at : Q[i]) {
      ans += kaede.get(at + 1, in.size() - 1);
    }
  }
  for (int j = int(0); j < int(out.size()); j++) {
    int at = out[j];
    int mn = INF, mx = -INF, cnt = 0;
    for (int i = int(0); i < int(in.size()); i++) {
      if (ex[at][in[i]]) {
        cnt++;
        chmin(mn, i);
        chmax(mx, i);
      }
    }
    if (cnt == 0) {
      ans += out.size() - 1 - j;
    } else {
      assert(mx - mn + 1 == cnt);
      int p = fuyuko.get(mn, mx);
      if (j < p) ans += p - j - 1;
    }
  }
  cout << ans << endl;
}
signed main() {
  cin.tie(0);
  ios::sync_with_stdio(0);
  cout << fixed << setprecision(20);
  solve();
}
