#include <bits/stdc++.h>
using namespace std;
const int maxn = 200100 << 1;
namespace SAM {
int tot = 1, last = 1;
struct node {
  int fa, ch[30], len, pos;
} dian[maxn];
void add(int c, int Pos) {
  int p = last, np = last = ++tot;
  dian[np].len = dian[p].len + 1;
  dian[np].pos = Pos;
  for (; p && !dian[p].ch[c]; p = dian[p].fa) dian[p].ch[c] = np;
  if (!p)
    dian[np].fa = 1;
  else {
    int q = dian[p].ch[c];
    if (dian[q].len == dian[p].len + 1)
      dian[np].fa = q;
    else {
      int nq = ++tot;
      dian[nq] = dian[q];
      dian[nq].len = dian[p].len + 1;
      dian[q].fa = dian[np].fa = nq;
      for (; p && dian[p].ch[c] == q; p = dian[p].fa) dian[p].ch[c] = nq;
    }
  }
}
}  // namespace SAM
namespace Segment_tree {
int tot, ls[maxn * 20], rs[maxn * 20], root[maxn * 20], val[maxn * 20];
void insert(int pos, int l, int r, int &rt) {
  if (!rt) rt = ++tot;
  if (l == r) {
    val[rt]++;
    return;
  }
  int mid = l + r >> 1;
  if (pos <= mid)
    insert(pos, l, mid, ls[rt]);
  else
    insert(pos, mid + 1, r, rs[rt]);
  val[rt] = val[ls[rt]] + val[rs[rt]];
}
int query(int L, int R, int l, int r, int rt) {
  if (L < 1 || R < 1 || L > R) return 0;
  if (L <= l && r <= R) return val[rt];
  int mid = l + r >> 1, ret = 0;
  if (L <= mid) ret += query(L, R, l, mid, ls[rt]);
  if (R > mid) ret += query(L, R, mid + 1, r, rs[rt]);
  return ret;
}
int merge(int x, int y) {
  if (!x || !y) return x + y;
  int rt = ++tot;
  val[rt] = val[x] + val[y];
  ls[rt] = merge(ls[x], ls[y]);
  rs[rt] = merge(rs[x], rs[y]);
  return rt;
}
}  // namespace Segment_tree
using namespace SAM;
using namespace Segment_tree;
char s[maxn];
vector<int> v[maxn];
int ans = 1, f[maxn], len, top[maxn];
void dfs1(int x) {
  int siz = v[x].size();
  for (int i = 0; i < siz; i++) {
    int y = v[x][i];
    dfs1(y);
    if (x != 1) root[x] = merge(root[x], root[y]);
  }
}
void dfs2(int x) {
  for (int i = 0; i < v[x].size(); i++) {
    int y = v[x][i];
    int flag = query(dian[y].pos - (dian[y].len - dian[top[x]].len),
                     dian[y].pos - 1, 1, len, root[top[x]]);
    if (flag)
      f[y] = f[x] + 1, top[y] = y;
    else
      f[y] = f[x], top[y] = top[x];
    dfs2(y);
  }
  ans = max(ans, f[x]);
}
int main() {
  scanf("%d", &len);
  scanf("%s", s + 1);
  for (int i = 1; i <= len; i++)
    add(s[i] - 'a', i), insert(i, 1, len, root[last]);
  for (int i = 1; i <= SAM::tot; i++)
    v[dian[i].fa].push_back(i), f[i] = (dian[i].fa == 1) ? 1 : 0,
                                top[i] = (dian[i].fa == 1) ? i : 0;
  dfs1(1);
  for (int i = 0; i < v[1].size(); i++) dfs2(v[1][i]);
  cout << ans;
}
