structEdge { int to, next; } e[maxn * 2]; int c1, head[maxn], in[maxn]; inlinevoidadd_edge(int u, int v){ e[c1].to = v; ++in[v]; e[c1].next = head[u]; head[u] = c1++; }
#define ch s[i] - 'a' structAC_automaton { int nxt[26], v, fail; } T[maxn]; int top = 1, rt = 1, id[maxn]; intinsert(char *s){ int now = rt, l = strlen(s); for (int i = 0; i < l; ++i) { if (!T[now].nxt[ch]) T[now].nxt[ch] = ++top; now = T[now].nxt[ch]; } ++T[now].v; return now; }
voidinit_fail(){ queue<int> Q; for (int i = 0; i < 26; ++i) { int &u = T[rt].nxt[i]; if (!u) { u = rt; continue; } T[u].fail = rt; Q.push(u); } while (!Q.empty()) { int u = Q.front(); Q.pop(); for (int i = 0; i < 26; ++i) { int &v = T[u].nxt[i]; if (!v) { v = T[T[u].fail].nxt[i]; continue; } T[v].fail = T[T[u].fail].nxt[i]; Q.push(v); } } for (int i = 2; i <= top; ++i) add_edge(T[i].fail, i); }
int f[maxn]; voidtopsort(){ queue<int> Q; for (int i = 1; i <= top; ++i) if (!in[i]) Q.push(i); while (!Q.empty()) { int u = Q.front(); Q.pop(); f[u] += T[u].v; for (int i = head[u]; ~i; i = e[i].next) { int v = e[i].to; f[v] = max(f[v], f[u]); if (--in[v] == 0) Q.push(v); } } }
int use[maxn]; intmain(){ fill(head, head + maxn, -1); ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
cin >> n; for (int i = 1; i <= n; ++i) { l[i] = r[i - 1] + 1; cin >> s + l[i]; r[i] = l[i] + strlen(s + l[i]) - 1; id[i] = insert(s + l[i]); } init_fail(); for (int i = 1; i <= n; ++i) { if (use[id[i]]) continue; use[id[i]] = 1; int now = rt; for (int j = l[i]; j <= r[i]; ++j) { now = T[now].nxt[s[j] - 'a']; if (id[i] != now) add_edge(now, id[i]); } } topsort(); cout << *max_element(f + 1, f + top + 1) << "\n"; return0; }