#include <bits/stdc++.h>
using namespace std;
int son[20000050][2], pcnt;
int root[400050], n;
char str[200050];
void Update(int &rt, int l, int r, int ps) {
  if (!rt) rt = ++pcnt;
  if (l == r) return;
  int mid = (l + r) >> 1;
  if (mid >= ps)
    Update(son[rt][0], l, mid, ps);
  else
    Update(son[rt][1], mid + 1, r, ps);
}
bool Query(int rt, int l, int r, int ll, int rr) {
  if (!rt) return 0;
  if (ll <= l && r <= rr) return 1;
  int mid = (l + r) >> 1;
  if (mid >= ll && Query(son[rt][0], l, mid, ll, rr)) return 1;
  if (mid < rr && Query(son[rt][1], mid + 1, r, ll, rr)) return 1;
  return 0;
}
int Merge(int rt1, int rt2) {
  if (!rt1) return rt2;
  if (!rt2) return rt1;
  int rt = ++pcnt;
  son[rt][0] = Merge(son[rt1][0], son[rt2][0]);
  son[rt][1] = Merge(son[rt1][1], son[rt2][1]);
  return rt;
}
int buc[200050];
struct SAM {
  int son[400050][26];
  int len[400050], po[400050];
  int pcnt, par[400050], lst;
  int nw[400050], dp[400050];
  int pos[400050];
  void init() { lst = pcnt = 1; }
  int new_node() { return ++pcnt; }
  void ins(int ps, int c) {
    int p = lst;
    int cur = new_node();
    len[cur] = len[p] + 1;
    po[cur] = ps;
    while (p && !son[p][c]) son[p][c] = cur, p = par[p];
    if (!p)
      par[cur] = 1;
    else {
      int q = son[p][c];
      if (len[q] == len[p] + 1)
        par[cur] = q;
      else {
        int clone = new_node();
        memcpy(son[clone], son[q], sizeof(son[clone]));
        par[clone] = par[q];
        len[clone] = len[p] + 1;
        po[clone] = ps;
        while (p && son[p][c] == q) son[p][c] = clone, p = par[p];
        par[cur] = par[q] = clone;
      }
    }
    lst = cur;
  }
  void Build() {
    int maxn = 0;
    for (int i = 1; i <= pcnt; ++i) buc[len[i]]++, maxn = max(maxn, len[i]);
    for (int i = 1; i <= n; ++i) buc[i] += buc[i - 1];
    for (int i = 1; i <= pcnt; ++i) nw[buc[len[i]]--] = i;
    for (int i = pcnt; i >= 2; --i) {
      Update(root[nw[i]], 1, n, po[nw[i]]);
      root[par[nw[i]]] = Merge(root[par[nw[i]]], root[nw[i]]);
    }
    int ans = 0;
    for (int i = 2; i <= pcnt; ++i) {
      int p = nw[i];
      if (par[p] == 1)
        dp[p] = 1, pos[p] = p;
      else if (Query(root[pos[par[p]]], 1, n, po[p] - len[p] + len[pos[par[p]]],
                     po[p] - 1))
        dp[p] = dp[par[p]] + 1, pos[p] = p;
      else
        dp[p] = dp[par[p]], pos[p] = pos[par[p]];
      ans = max(ans, dp[p]);
    }
    printf("%d\n", ans);
  }
} SAM;
int main() {
  scanf("%d %s", &n, str + 1);
  SAM.init();
  for (int i = 1; i <= n; ++i) SAM.ins(i, str[i] - 'a');
  SAM.Build();
}
