#include <bits/stdc++.h>
using namespace std;
template <typename T>
inline void read(T &n) {
  T w = 1;
  n = 0;
  char ch = getchar();
  while (!isdigit(ch) && ch != EOF) {
    if (ch == '-') w = -1;
    ch = getchar();
  }
  while (isdigit(ch) && ch != EOF) {
    n = (n << 1) + (n << 3) + (ch & 15);
    ch = getchar();
  }
  n *= w;
}
const int N = 4e5 + 5;
int n, dp[N << 1], d, las = 1, cnt = 1, ans = 1, fa[N << 1], pos[N << 1];
int ch[N << 1][26], len[N << 1], fr[N << 1];
char s[N];
void ins(int c, int i) {
  int p = las, np = las = ++cnt;
  pos[np] = i;
  len[np] = len[p] + 1;
  for (; p && !ch[p][c]; p = fa[p]) ch[p][c] = np;
  if (p == 0)
    fa[np] = 1;
  else {
    int q = ch[p][c];
    if (len[q] == len[p] + 1)
      fa[np] = q;
    else {
      int nq = ++cnt;
      len[nq] = len[p] + 1;
      fa[nq] = fa[q];
      pos[nq] = pos[q];
      memcpy(ch[nq], ch[q], sizeof(ch[nq]));
      fa[np] = fa[q] = nq;
      for (; p && ch[p][c] == q; p = fa[p]) ch[p][c] = nq;
    }
  }
}
int tot = 0, root[N << 1], lc[N * 20], rc[N * 20], rk[N << 1], tong[N << 1];
void upd(int &k, int l, int r, int x) {
  if (!k) k = ++tot;
  if (l == r) return;
  int mid = (l + r) >> 1;
  if (x <= mid)
    upd(lc[k], l, mid, x);
  else
    upd(rc[k], mid + 1, r, x);
}
int merge(int x, int y, int l, int r) {
  if (!x || !y) return x + y;
  int mid = (l + r) >> 1, f = ++tot;
  if (l != r) {
    lc[f] = merge(lc[x], lc[y], l, mid);
    rc[f] = merge(rc[x], rc[y], mid + 1, r);
  }
  return f;
}
int doQuery(int k, int l, int r, int L, int R) {
  if (!k || l > R || r < L) return 0;
  if (l >= L && r <= R) return 1;
  int mid = (l + r) >> 1;
  return doQuery(lc[k], l, mid, L, R) || doQuery(rc[k], mid + 1, r, L, R);
}
void Sort() {
  for (int i = 1; i <= cnt; i++) tong[len[i]]++;
  for (int i = 1; i <= n; i++) tong[i] += tong[i - 1];
  for (int i = 1; i <= cnt; i++) rk[tong[len[i]]--] = i;
}
int main() {
  read(n);
  scanf("%s", s + 1);
  for (int i = 1; i <= n; i++) {
    ins(s[i] - 'a', i);
    upd(root[las], 1, n, i);
  }
  Sort();
  for (int i = cnt; i > 1; i--) {
    int u = rk[i], v = fa[u];
    root[v] = merge(root[v], root[u], 1, n);
  }
  for (int i = 2; i <= cnt; i++) {
    int u = rk[i], v = fa[u];
    if (v == 1) {
      dp[u] = 1;
      fr[u] = u;
    } else if (doQuery(root[fr[v]], 1, n, pos[u] - len[u] + len[fr[v]],
                       pos[u] - 1)) {
      dp[u] = dp[v] + 1;
      fr[u] = u;
    } else {
      dp[u] = dp[v];
      fr[u] = fr[v];
    }
    ans = max(ans, dp[u]);
  }
  printf("%d", ans);
  return 0;
}
