#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> ii;
const int INF = 1e9;
const ll LINF = 1e18;
const int p = 31;
const int MOD = 1e9 + 9277;
const int MX = 1e6 + 5;
const int N = 1e6 + 5;
int n;
string s[N];
int sz[N];
int p_pow[MX], inv_p_pow[MX];
vector<int> h[N], rev_h[N];
int binpow(int a, int b) {
int ans = 1;
for (; b > 0; b >>= 1) {
if (b & 1) ans = 1ll * ans * a % MOD;
a = 1ll * a * a % MOD;
}
return ans;
}
void precompute() {
p_pow[0] = 1;
for (int i = 1; i < MX; i++) p_pow[i] = 1ll * p_pow[i - 1] * p % MOD;
inv_p_pow[MX - 1] = binpow(p_pow[MX - 1], MOD - 2);
for (int i = MX - 2; i >= 0; i--) inv_p_pow[i] = 1ll * inv_p_pow[i + 1] * p % MOD;
}
void computeHash(int i, const string& s, int sz) {
h[i] = rev_h[i] = vector<int>(sz + 1);
h[i][0] = rev_h[i][0] = 0;
for (int j = 1; j <= sz; j++) {
h[i][j] = (1ll * h[i][j - 1] * p + (s[j] - 'a' + 1)) % MOD;
rev_h[i][j] = (rev_h[i][j - 1] + 1ll * p_pow[j - 1] * (s[j] - 'a' + 1) % MOD) % MOD;
}
}
int getHash(int i, int l, int r) {
return (h[i][r] - 1ll * h[i][l - 1] * p_pow[r - l + 1] % MOD + MOD) % MOD;
}
int getRevHash(int i, int l, int r) {
return 1ll * (rev_h[i][r] - rev_h[i][l - 1] + MOD) % MOD * inv_p_pow[l - 1] % MOD;
}
bool isPalin(int i, int l, int r) {
return (getHash(i, l, r) == getRevHash(i, l, r));
}
struct Node {
int nxt[26];
int mark = 0;
Node() {
memset(nxt, -1, sizeof nxt);
}
};
struct PrefixTrie {
vector<Node> trie;
PrefixTrie() {
trie = vector<Node>(1);
}
void addString(const string& s, int sz) {
int v = 0;
for (int i = 1; i <= sz; i++) {
int c = s[i] - 'a';
if (trie[v].nxt[c] == -1) {
trie[v].nxt[c] = trie.size();
trie.push_back(Node());
}
v = trie[v].nxt[c];
}
trie[v].mark++;
}
};
PrefixTrie PrefTrie;
struct SuffixTrie {
vector<Node> trie;
SuffixTrie() {
trie = vector<Node>(1);
}
void addString(const string& s, int sz) {
int v = 0;
for (int i = sz; i >= 1; i--) {
int c = s[i] - 'a';
if (trie[v].nxt[c] == -1) {
trie[v].nxt[c] = trie.size();
trie.push_back(Node());
}
v = trie[v].nxt[c];
}
trie[v].mark++;
}
};
SuffixTrie SufTrie;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n;
precompute();
for (int i = 1; i <= n; i++) {
cin >> sz[i];
cin >> s[i];
s[i] = ' ' + s[i];
computeHash(i, s[i], sz[i]);
PrefTrie.addString(s[i], sz[i]);
SufTrie.addString(s[i], sz[i]);
}
// sz[i] >= sz[j]
ll ans = 0;
for (int i = 1; i <= n; i++) {
int v = 0;
for (int k = 1; k <= sz[i]; k++) {
int c = s[i][k] - 'a';
v = SufTrie.trie[v].nxt[c];
if (v == -1) break;
ans += isPalin(i, k + 1, sz[i]) * SufTrie.trie[v].mark;
}
}
// sz[i] < sz[j]
for (int j = 1; j <= n; j++) {
int v = 0;
for (int k = sz[j]; k >= 2; k--) {
int c = s[j][k] - 'a';
v = PrefTrie.trie[v].nxt[c];
if (v == -1) break;
ans += isPalin(j, 1, k - 1) * PrefTrie.trie[v].mark;
}
}
cout << ans << '\n';
}