#include <bits/stdc++.h>
using namespace std;
namespace Graph {
struct Node {
  vector<Node*> conn;
  vector<int> spos;
  int index;
};
struct Graph {
  int n;
  vector<Node> nodes;
  void setSpos() {
    for (auto& node : nodes) node.spos.push_back(node.conn.size());
  }
  Graph(int nsize) {
    n = nsize;
    nodes.resize(n);
    for (int i = 0; i < n; i++) nodes[i].index = i;
    setSpos();
  }
  void addEdge(int a, int b) {
    Node *u = &nodes[a], *v = &nodes[b];
    u->conn.push_back(v);
  }
  vector<bool> valid;
  int l = 0, r = 0;
  void stateInit() { valid.resize(n, false); }
  void changeValid(int ind) { valid[ind] = !valid[ind]; }
  void setBounds(int nl, int nr) { l = nl, r = nr; }
  bool hasCycleDfs(Node* cur, vector<bool>& explr, vector<bool>& deadend) {
    int ind = cur->index;
    if (explr[ind]) return true;
    explr[ind] = true;
    for (int i = cur->spos[l]; i < cur->spos[r]; i++) {
      Node* next = cur->conn[i];
      int nind = next->index;
      if (valid[nind] && !deadend[nind] && hasCycleDfs(next, explr, deadend))
        return true;
    }
    explr[ind] = false;
    deadend[ind] = true;
    return false;
  }
  bool hasCycle() {
    vector<bool> explr(n, false), deadend(n, false);
    for (int i = 0; i < n; i++)
      if (valid[i] && !deadend[i] && hasCycleDfs(&nodes[i], explr, deadend))
        return true;
    return false;
  }
};
};  // namespace Graph
namespace StringHash {
const int MOD = 1000000007;
struct Modint {
  int val;
  Modint(int nval = 0) { val = nval; }
  Modint& operator+=(Modint r) {
    val = (val + r.val) % MOD;
    return *this;
  }
  Modint operator+(Modint r) { return Modint(*this) += r; }
  Modint& operator-=(Modint r) {
    val = (val + MOD - r.val) % MOD;
    return *this;
  }
  Modint operator-(Modint r) { return Modint(*this) -= r; }
  Modint& operator*=(Modint r) {
    val = 1LL * val * r.val % MOD;
    return *this;
  }
  Modint operator*(Modint r) { return Modint(*this) *= r; }
};
bool operator==(Modint l, Modint r) { return l.val == r.val; }
const int ACCURACY = 1, maxN = 100000;
struct Hashfield {
  int n;
  vector<Modint> hash[ACCURACY];
  static Modint mult[256], base[ACCURACY][maxN + 1];
  static void init() {
    for (int i = 'a'; i <= 'z'; i++) mult[i] = i - 'a';
    for (int i = 0; i < ACCURACY; i++) {
      base[i][0] = 1;
      base[i][1] = 127 + i * 16;
      for (int j = 2; j <= maxN; j++) base[i][j] = base[i][j - 1] * base[i][1];
    }
  }
  void addChar(char c) {
    for (int i = 0; i < ACCURACY; i++)
      hash[i].push_back(hash[i].back() * base[i][1] + c);
  }
  Hashfield(string s = "") {
    for (int i = 0; i < ACCURACY; i++) {
      hash[i].push_back(0);
    }
    for (auto c : s) addChar(c);
  }
  vector<Modint> get(int l, int r) {
    vector<Modint> ret;
    for (int i = 0; i < ACCURACY; i++)
      ret.push_back(hash[i][r] - hash[i][l] * base[i][r - l]);
    return ret;
  }
};
Modint Hashfield::mult[256], Hashfield::base[ACCURACY][maxN + 1];
};  // namespace StringHash
int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(0);
  StringHash::Hashfield::init();
  int n;
  cin >> n;
  Graph::Graph* gp;
  {
    int totalsz = 0;
    vector<int> start(n + 1);
    vector<string> s(n);
    vector<StringHash::Hashfield> hf(n);
    for (int i = 0; i < n; i++) {
      cin >> s[i];
      start[i] = totalsz;
      totalsz += s[i].size();
      hf[i] = StringHash::Hashfield(s[i]);
    }
    start[n] = totalsz;
    gp = new Graph::Graph(1 + 2 * totalsz);
    int up = 1, down = 1 + totalsz;
    for (int j = 0; j < n; j++, gp->setSpos())
      for (int i = 0; i < n; i++) {
        if (s[i].size() > s[j].size() &&
            hf[i].get(0, s[j].size()) == hf[j].get(0, s[j].size())) {
          gp->addEdge(0, up + start[i] + s[j].size());
          gp->addEdge(0, down + start[i] + s[j].size());
        }
        for (size_t p = 1; p < s[i].size(); p++) {
          int len = min(s[i].size() - p, s[j].size());
          int diff = s[j].size() - (s[i].size() - p);
          if (hf[i].get(p, p + len) == hf[j].get(0, len)) {
            if (diff < 0) {
              gp->addEdge(up + start[i] + p, up + start[i] + p + len);
              gp->addEdge(down + start[i] + p, down + start[i] + p + len);
            } else if (diff == 0) {
              gp->addEdge(up + start[i] + p, 0);
              gp->addEdge(down + start[i] + p, 0);
            } else {
              gp->addEdge(up + start[i] + p, down + start[j] + len);
              gp->addEdge(down + start[i] + p, up + start[j] + len);
            }
          }
        }
      }
    gp->stateInit();
    gp->changeValid(0);
    int l = 0, r = 0, result = 0;
    while (1) {
      gp->setBounds(l, r);
      bool ret = gp->hasCycle();
      if (ret) {
        for (int i = start[l]; i < start[l + 1]; i++) {
          gp->changeValid(up + i);
          gp->changeValid(down + i);
        }
        l++;
      } else {
        result += r - l;
        if (r == n) break;
        for (int i = start[r]; i < start[r + 1]; i++) {
          gp->changeValid(up + i);
          gp->changeValid(down + i);
        }
        r++;
      }
    }
    cout << result << '\n';
  }
  return 0;
}
