#include <bits/stdc++.h>
clock_t t = clock();
namespace my_std {
using namespace std;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
template <typename T>
inline T rnd(T l, T r) {
  return uniform_int_distribution<T>(l, r)(rng);
}
template <typename T>
inline bool chkmax(T &x, T y) {
  return x < y ? x = y, 1 : 0;
}
template <typename T>
inline bool chkmin(T &x, T y) {
  return x > y ? x = y, 1 : 0;
}
template <typename T>
inline void read(T &t) {
  t = 0;
  char f = 0, ch = getchar();
  double d = 0.1;
  while (ch > '9' || ch < '0') f |= (ch == '-'), ch = getchar();
  while (ch <= '9' && ch >= '0') t = t * 10 + ch - 48, ch = getchar();
  if (ch == '.') {
    ch = getchar();
    while (ch <= '9' && ch >= '0') t += d * (ch ^ 48), d *= 0.1, ch = getchar();
  }
  t = (f ? -t : t);
}
template <typename T, typename... Args>
inline void read(T &t, Args &...args) {
  read(t);
  read(args...);
}
char __sr[1 << 21], __z[20];
int __C = -1, __zz = 0;
inline void Ot() { fwrite(__sr, 1, __C + 1, stdout), __C = -1; }
inline void print(register int x) {
  if (__C > 1 << 20) Ot();
  if (x < 0) __sr[++__C] = '-', x = -x;
  while (__z[++__zz] = x % 10 + 48, x /= 10)
    ;
  while (__sr[++__C] = __z[__zz], --__zz)
    ;
  __sr[++__C] = '\n';
}
void file() {}
inline void chktime() {}
long long ksm(long long x, int y) {
  long long ret = 1;
  for (; y; y >>= 1, x = x * x)
    if (y & 1) ret = ret * x;
  return ret;
}
}  // namespace my_std
using namespace my_std;
int n;
char s[404040];
namespace SGT {
int ls[404040 * 20], rs[404040 * 20], cnt;
void insert(int &k, int l, int r, int x) {
  if (!k) k = ++cnt;
  if (l == r) return;
  int mid = (l + r) >> 1;
  if (x <= mid)
    insert(ls[k], l, mid, x);
  else
    insert(rs[k], mid + 1, r, x);
}
int merge(int k1, int k2, int l, int r) {
  if (!k1 || !k2) return k1 + k2;
  int k = ++cnt;
  if (l == r) return k;
  int mid = (l + r) >> 1;
  ls[k] = merge(ls[k1], ls[k2], l, mid);
  rs[k] = merge(rs[k1], rs[k2], mid + 1, r);
  return k;
}
int query(int k, int l, int r, int x, int y) {
  if (!k) return 0;
  if (x <= l && r <= y) return 1;
  int mid = (l + r) >> 1;
  if (x <= mid && query(ls[k], l, mid, x, y)) return 1;
  if (y > mid && query(rs[k], mid + 1, r, x, y)) return 1;
  return 0;
}
}  // namespace SGT
namespace SAM {
struct hh {
  int ch[30], link, len;
} a[404040];
int pos[404040], root[404040];
int lst = 1, cnt = 1;
void insert(int c, int id) {
  int cur = ++cnt, p = lst;
  lst = cur;
  a[cur].len = a[p].len + 1;
  pos[cur] = id;
  SGT::insert(root[cur], 1, n, id);
  while (p && !a[p].ch[c]) a[p].ch[c] = cur, p = a[p].link;
  if (!p) return (void)(a[cur].link = 1);
  int q = a[p].ch[c];
  if (a[q].len == a[p].len + 1) return (void)(a[cur].link = q);
  int t = ++cnt;
  a[t] = a[q];
  a[t].len = a[p].len + 1;
  a[cur].link = a[q].link = t;
  while (p && a[p].ch[c] == q) a[p].ch[c] = t, p = a[p].link;
}
int cc[404040], id[404040];
void init() {
  for (int i = (2); i <= (cnt); i++) ++cc[a[i].len];
  for (int i = (1); i <= (n); i++) cc[i] += cc[i - 1];
  for (int i = (cnt); i >= (2); i--) id[cc[a[i].len]--] = i;
  for (int i = (cnt - 1); i >= (1); i--) {
    int x = id[i], fa = a[x].link;
    pos[fa] = pos[x];
    root[fa] = SGT::merge(root[fa], root[x], 1, n);
  }
}
int dp[404040], top[404040], ans;
void work() {
  top[1] = 1;
  for (int i = (1); i <= (cnt - 1); i++) {
    int x = id[i], fa = top[a[x].link];
    if (fa == 1 ||
        SGT::query(root[fa], 1, n, pos[x] - a[x].len + a[fa].len, pos[x] - 1))
      top[x] = x, chkmax(ans, dp[x] = dp[fa] + 1);
    else
      top[x] = fa;
  }
  cout << ans;
}
}  // namespace SAM
int main() {
  file();
  read(n);
  cin >> (s + 1);
  for (int i = (1); i <= (n); i++) SAM::insert(s[i] - 'a' + 1, i);
  SAM::init();
  SAM::work();
  return 0;
}
