#include <bits/stdc++.h>
using namespace std;
const int INF = 1791791791;
const long long INFLL = 1791791791791791791ll;
template <int input_buf_size, int output_buf_size>
class FastIO {
  char cbuf[input_buf_size + 1];
  int icur = 0;
  inline bool go_to_next_token() {
    while (cbuf[icur] == ' ' || cbuf[icur] == '\n') icur++;
    while (cbuf[icur] == 0) {
      icur = 0;
      if (fgets(cbuf, sizeof(cbuf), stdin) != cbuf) return false;
      while (cbuf[icur] == ' ' || cbuf[icur] == '\n') icur++;
    }
    return true;
  }

 public:
  string readString() {
    assert(go_to_next_token());
    string ans;
    while (cbuf[icur] != ' ' && cbuf[icur] != '\n' && cbuf[icur] != 0)
      ans.push_back(cbuf[icur++]);
    ans.shrink_to_fit();
    return ans;
  }
  template <class int_type>
  int_type readInt() {
    assert(go_to_next_token());
    int_type x = 0;
    bool m = cbuf[icur] == '-';
    if (m) icur++;
    while ('0' <= cbuf[icur] && cbuf[icur] <= '9') {
      x *= 10;
      x += (cbuf[icur] - '0');
      icur++;
    }
    if (m) x = -x;
    return x;
  }
  bool seekEof() { return !go_to_next_token(); }

 private:
  char obuf[output_buf_size + 1];
  int ocur = 0;
  inline void write_string(const char* str, size_t sz = 0) {
    if (sz == 0) sz = strlen(str);
    if (ocur + sz > output_buf_size) {
      fputs(obuf, stdout);
      fputs(str, stdout);
      ocur = 0;
      obuf[0] = 0;
      return;
    }
    strcpy(obuf + ocur, str);
    ocur += sz;
    obuf[ocur] = 0;
  }

 public:
  template <class int_type>
  void writeInt(int_type x, bool sp = true) {
    char buf[20];
    int c = 0;
    if (x < 0) {
      buf[c++] = '-';
      x = -x;
    }
    int s = c;
    if (x == 0) {
      buf[c++] = '0';
    }
    while (x > 0) {
      buf[c++] = (x % 10) + '0';
      x /= 10;
    }
    for (int i = 0; 2 * i < c - s; i++) {
      swap(buf[s + i], buf[c - 1 - i]);
    }
    buf[c] = 0;
    write_string(buf, c);
    if (sp) write_string(" ", 1);
  }
  void writeString(string s, bool space = true) {
    write_string(s.c_str(), s.size());
    if (space) write_string(" ", 1);
  }
  void writeEndl() { write_string("\n", 1); }
  void flush() {
    fputs(obuf, stdout);
    ocur = 0;
    obuf[0] = 0;
  }

 private:
  bool lflush;

 public:
  FastIO(bool local_flush) {
    obuf[0] = 0;
    lflush = local_flush;
  }
  ~FastIO() { fputs(obuf, stdout); }
};
FastIO<10000000, 10000000> IO(true);
class hashed_string {
  static const long long p = 179;
  static const long long MOD = 1000 * 1000 * 1000 + 7;
  static vector<long long> pps;
  string s;
  vector<long long> h;

 public:
  hashed_string() {}
  hashed_string(const string& _s) {
    s = _s;
    while (pps.size() < s.size() + 1)
      pps.push_back(((((pps.back() * p) % (MOD)) + (MOD)) % (MOD)));
    h.resize(s.size() + 1, 0);
    for (int i = 0; i < ((int)(s.size())); ++i)
      h[i + 1] = ((((h[i] * p + (s[i] - 'a' + 1)) % (MOD)) + (MOD)) % (MOD));
  }
  long long substr_hash(int l, int r) const {
    return ((((h[r + 1] - h[l] * pps[r - l + 1]) % (MOD)) + (MOD)) % (MOD));
  }
  size_t size() const { return s.size(); }
  const char& operator[](int i) const { return s[i]; }
  operator string() const { return s; }
};
vector<long long> hashed_string::pps = {1};
class digraph {
 private:
  vector<vector<int> > mapper;

 protected:
  int cn = 0;
  inline int vnum(int wh, int i) { return mapper[wh][i]; }
  vector<vector<int> > edges;

 public:
  digraph() {}
  int add_vertex_class(int sz = -1) {
    mapper.push_back(vector<int>());
    if (sz > -1) {
      mapper.back().resize(sz);
      iota((mapper.back()).begin(), (mapper.back()).end(), cn);
      cn += sz;
      while ((int)edges.size() < cn) edges.push_back(vector<int>());
    }
    return mapper.size() - 1;
  }
  void add_vertice_to_class(int cl) {
    mapper[cl].push_back(cn++);
    edges.push_back(vector<int>());
  }
  void add_edge(int ucl, int ui, int vcl, int vi) {
    edges[vnum(ucl, ui)].push_back(vnum(vcl, vi));
  }
};
class kosaraju_scc_finder : public digraph {
  vector<int> tsort;
  vector<int> cnum;
  vector<int> csize;
  vector<bool> vis;
  vector<vector<int> > rev_edges;
  void topsort(int v) {
    vis[v] = true;
    for (int u : edges[v])
      if (!vis[u]) topsort(u);
    tsort.push_back(v);
  }
  void dfs(int u, int cm) {
    cnum[u] = cm;
    csize[cm]++;
    for (int v : rev_edges[u])
      if (cnum[v] == -1) dfs(v, cm);
  }

 public:
  kosaraju_scc_finder() {}
  void process() {
    vis.resize(cn, false);
    for (int i = 0; i < ((int)(cn)); ++i)
      if (!vis[i]) topsort(i);
    reverse((tsort).begin(), (tsort).end());
    rev_edges.resize(cn);
    for (int i = 0; i < ((int)(cn)); ++i)
      for (int u : edges[i]) rev_edges[u].push_back(i);
    cnum.resize(cn, -1);
    for (int v : tsort) {
      if (cnum[v] == -1) {
        csize.push_back(0);
        dfs(v, csize.size() - 1);
      }
    }
  }
  int num_in_comp(int vcl, int vi) { return csize[cnum[vnum(vcl, vi)]]; }
};
vector<vector<vector<vector<pair<int, int> > > > > all_edges;
void get_edges(const vector<hashed_string>& strs) {
  int n = strs.size();
  all_edges.resize(n);
  for (int i = 0; i < ((int)(n)); ++i) {
    all_edges[i].resize(n);
    for (int j = 0; j < ((int)(n)); ++j) all_edges[i][j].resize(n);
  }
  for (int i = 0; i < ((int)(n)); ++i) {
    for (int k = 0; k < ((int)(strs[i].size())); ++k) {
      for (int j = 0; j < ((int)(n)); ++j) {
        int len = min(strs[i].size() - k, strs[j].size());
        if (strs[i].substr_hash(k, k + len - 1) ==
            strs[j].substr_hash(0, len - 1)) {
          if (strs[j].size() == strs[i].size() - k) {
            for (int t = 0; t < ((int)(n)); ++t) {
              all_edges[i][t][j].push_back(make_pair(k, 0));
            }
          } else if (strs[j].size() < strs[i].size() - k) {
            all_edges[i][i][j].push_back(make_pair(k, k + len));
          } else {
            all_edges[i][j][i].push_back(make_pair(k, len));
          }
        }
      }
    }
  }
}
bool is_stable(const vector<hashed_string>& strs, int l, int r) {
  r++;
  kosaraju_scc_finder graph;
  int n = strs.size();
  for (int i = 0; i < ((int)(n)); ++i) {
    if (l <= i && i < r)
      graph.add_vertex_class(strs[i].size());
    else
      graph.add_vertex_class();
  }
  for (int i = (int)(l); i < ((int)(r)); ++i) {
    for (int j = (int)(l); j < ((int)(r)); ++j) {
      for (int k = (int)(l); k < ((int)(r)); ++k) {
        for (auto p : all_edges[i][j][k]) {
          if (i == j && p.first == p.second && p.first != 0) return false;
          graph.add_edge(i, p.first, j, p.second);
        }
      }
    }
  }
  graph.process();
  for (int i = (int)(l); i < ((int)(r)); ++i) {
    for (int j = (int)(1); j < ((int)(strs[i].size())); ++j) {
      if (graph.num_in_comp(i, j) > 1) return false;
    }
  }
  return true;
}
int max_right(const vector<hashed_string>& strs, int l) {
  int lt = l - 1;
  int rt = strs.size();
  while (lt < rt - 1) {
    int mid = (lt + rt) >> 1;
    if (is_stable(strs, l, mid))
      lt = mid;
    else
      rt = mid;
  }
  return lt;
}
int main() {
  int n = IO.readInt<int>();
  vector<hashed_string> strs(n);
  for (hashed_string& s : strs) s = IO.readString();
  get_edges(strs);
  int ans = 0;
  for (int i = 0; i < ((int)(n)); ++i) {
    ans += max_right(strs, i) - i + 1;
  }
  IO.writeInt(ans);
  IO.writeEndl();
  return 0;
}
