#include <bits/stdc++.h>
int n;
char S[300000];
struct edge {
  int to, nxt;
} E[500000];
int H[500000], tot;
inline void add_edge(int a, int b) { E[++tot] = (edge){b, H[a]}, H[a] = tot; }
struct SegmentTree {
  struct node {
    node *L, *R;
    node() { L = R = NULL; }
  };
  node *root;
  void insert(node *&now, int l, int r, int k) {
    if (!now) now = new node;
    if (l == r) return;
    int mdl = (l + r) >> 1;
    if (k <= mdl)
      insert(now->L, l, mdl, k);
    else
      insert(now->R, mdl + 1, r, k);
  }
  bool query(node *now, int l, int r, int L, int R) {
    if (l > R || r < L || !now) return false;
    if (L <= l && r <= R) return true;
    int mdl = (l + r) >> 1;
    return query(now->L, l, mdl, L, R) | query(now->R, mdl + 1, r, L, R);
  }
  SegmentTree() { root = NULL; }
};
SegmentTree::node *merge(SegmentTree::node *&A, SegmentTree::node *&B) {
  if (!(A && B)) return A ? A : B;
  SegmentTree::node *nw = new SegmentTree::node;
  nw->L = merge(A->L, B->L), nw->R = merge(A->R, B->R);
  return nw;
}
struct SAM {
  struct node {
    int son[26], len, link, R;
    SegmentTree S;
    node() {
      memset(son, 0xff, sizeof(int) * 26);
      len = link = R = 0;
    }
  } T[500000];
  int tot, lst;
  void insert(char C) {
    C -= 'a';
    int q = ++tot, p = lst;
    T[q].len = T[p].len + 1,
    T[q].S.insert(T[q].S.root, 1, n, T[q].R = T[q].len);
    lst = q;
    while (~p && !~T[p].son[C]) T[p].son[C] = q, p = T[p].link;
    if (!~p) return;
    int np = T[p].son[C];
    if (T[p].len + 1 == T[np].len)
      T[q].link = np;
    else {
      int nq = ++tot;
      memcpy(T[nq].son, T[np].son, sizeof(int) * 26);
      T[nq].link = T[np].link;
      T[nq].len = T[p].len + 1;
      T[np].link = T[q].link = nq;
      while (~p && T[p].son[C] == np) T[p].son[C] = nq, p = T[p].link;
    }
  }
  SAM() { tot = lst = 0, T[0].link = -1; }
} G;
void pre(int now) {
  for (int i = H[now]; i; i = E[i].nxt) {
    pre(E[i].to);
    G.T[now].R = std::max(G.T[now].R, G.T[E[i].to].R);
    G.T[now].S.root = merge(G.T[now].S.root, G.T[E[i].to].S.root);
  }
}
int Ans;
void solve(int now, int ans, int top) {
  Ans = std::max(Ans, ans);
  for (int i = H[now]; i; i = E[i].nxt) {
    if (G.T[top].S.query(G.T[top].S.root, 1, n,
                         G.T[E[i].to].R - G.T[E[i].to].len + G.T[top].len,
                         G.T[E[i].to].R - 1))
      solve(E[i].to, ans + 1, E[i].to);
    else
      solve(E[i].to, ans, top);
  }
}
int main() {
  scanf("%d%s", &n, S + 1);
  if (n == 1) return puts("1"), 0;
  for (int i = 1; i <= n; i++) G.insert(S[i]);
  for (int i = 1; i <= G.tot; i++) add_edge(G.T[i].link, i);
  pre(0), solve(0, 0, 0);
  printf("%d\n", Ans);
}
